LoginSignup
6
1

Elixirで言語処理100本ノックやってみた!vol.4

Posted at

こんにちは!
3ヶ月で、Elixir言語で開発できるようになるため、奮闘中のこーへーです!

今回のvol.4はめちゃくちゃ時間がかかりました。おそらくトータルで、20時間くらい。笑
たった1問に20時間もかかるのか!?って思うけど、実際にかかったんで、なんとも言えませんね。笑

とはいえ、この1問にはめちゃくちゃ成長させられました。
正直、かなり書き方調べたし、Elixirでif文って使っていいの?(ソース内で使ってるんですが)みたいな葛藤とかもあったりして、とにかく色々試してなんとか正解に辿りつきました。

当たり前のことだけど、やり切ることは重要だなって実感しました。
やり切るってなかなか精神的にハードルの高いことだと思います。最後までやり切れる人たちばっかの世の中なら、成功者だらけになるでしょ?そういうイメージですよ。

はい、ということで、100本ノックvol.4をやっていきたいと思います。
100本ノックの記事はこちら


04.元素記号Permalink

“Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.”という文を単語に分解し,1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字,それ以外の単語は先頭の2文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.

1.ゴール(結果)を知る

僕は問題文を読んで、頭の中は、「?」でした。
理解に苦しんだのは、「取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.」
」のあたり。
これは、専門用語を知っているか、読解力があるかで、人それぞれ違うので仕方ないんですが、僕はこの文章からだと、どんな結果を作れば良いのかイメージがつきづらかったです。
なので、『100本ノック解答』などと検索して調べ、ゴールを知るところから始めました。

まず、どんな結果を生み出したいのかイメージができなければ、方向性を間違う可能性があるということです。

2. 初めの一歩

次に、結果にたどり着くための一つ目のプログラムは何をしなければならないのか手順をノートなどに書き出し、道のりをより具体的にしました。
今回の場合、「文を単語に分解する」ことが、最初に行うべきプログラムです。そのプログラムが以下になります。

# String.splitで各単語を分解しリストに格納
String.split("Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.")

3. おおよそ15時間悩んだ部分

ある程度は、順当にプログラムを組むことができたんですが、あるところまでくると僕の知識では、超えられない壁がありました。
それは、「それ以外の単語は先頭の2文字を取り出し」の部分。

その手前の「1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字」を取り出すというのは、なんだかんだできたんですが、同時に一つのプログラムの中でこれを実現するのは無理なんじゃないか?と、色んな関数を試してみたり、裏技的な関数が用意されているんじゃないかと探したりしました。笑

4. 条件で分るという初歩的な結論に

なんだかんだ、たった1問に、悩みに悩み抜くと少しずつ正解に近づいていくもので、これって条件で分けたらええやん!と、ふと当たり前のことが閃きました。

ここからは、結構早く、一旦シンプルにif文で回して見ようといくつかのパターンを試しました。その中でつまづいたのは、要素ごとに取得したい文字数は違うのに、elseで分岐できなかった部分です。以下にソースを記載します。

if [1, 5, 6, 7, 8, 9, 15, 16, 19] do
...(28)> {String.slice(x, 0..0), y}
...(28)> else
...(28)> {String.slice(x, 0..1), y}
...(28)> end
...(28)> end)
[
  {"H", 1},
  {"H", 2},
  {"L", 3},
  {"B", 4},
  {"B", 5},
  {"C", 6},
  {"N", 7},
  {"O", 8},
  {"F", 9},
  {"N", 10},
  {"N", 11},
  {"M", 12},
  {"A", 13},
  {"S", 14},
  {"P", 15},
  {"S", 16},
  {"C", 17},
  {"A", 18},
  {"K", 19},
  {"C", 20}
]

ここで、if文の条件で関数を埋め込んで良いという事実を知り、Enum.member?を使うことにしました。
これでようやくうまくいったわけです。

解答

String.split("Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.") |> Enum.with_index(1) |> Enum.map(fn {x, y} -> if Enum.member?(base_list, y) do
...(33)> {String.slice(x, 0..0), y}
...(33)> else
...(33)> {String.slice(x, 0..1), y}
...(33)> end
...(33)> end)
[
  {"H", 1},
  {"He", 2},
  {"Li", 3},
  {"Be", 4},
  {"B", 5},
  {"C", 6},
  {"N", 7},
  {"O", 8},
  {"F", 9},
  {"Ne", 10},
  {"Na", 11},
  {"Mi", 12},
  {"Al", 13},
  {"Si", 14},
  {"P", 15},
  {"S", 16},
  {"Cl", 17},
  {"Ar", 18},
  {"K", 19},
  {"Ca", 20}
]

まとめ

この問題には、成長させられた実感があります。特に、ひとつひとつのプロセスを考えることの重要性がわかりました。飛び越えて実現するこはできないということですね。
まだ、100本ノック4つ目の問題なのにむちゃくちゃ時間かけてしまいましたが、実りある時間でした。

プログラミングを頑張っているみなさんもぜひ、意識してもらえたら嬉しいです。

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1