トピック
昨日、無事に第2回の勉強会を開催させて頂きました
第1回目では方針を決める時間が長く、手を動かす時間が全くなかったのですが
今回の勉強会では「パイプ演算子を触る」というテーマで
普通に真面目に勉強しました(そこそこ真面目に
第1回では参加者は僕を含めて2人だったのですが、 今回、新たな方に参加して頂けまして3人での勉強会となりました
清流elixir-infomation
開催場所: 丸の内(愛知)
人数: 2 -> 3 update!!
コミュニティ参加人数 : 2 -> 4 update!!
20190413現在
第2回の活動内容
Enumについて
パイプ演算子を使ってデータをごちゃごちゃやりましょうっていうテーマで
どれだけelixirがデータ処理に対して強力なのかを体験しました
合わせてEnumモジュールについての知識が必要になりましたのでざっくりと解説しました
優しく始めるelixirのEnumと簡単な使用例の方でそこそこ詳しく解説してますので
参考にして頂ければ幸いです
Enumモジュールが使えるデータ構造は以下の3つ
- リスト(list [])
- レンジ(range n..n+m)
- マップ(map %{})
このEnumとパイプ演算子の組み合わせがどれだけヤバいかを触ることに
パイプ演算子について
numbers = [1, 2, 3, 4, 5] res = func1(numbers) res = func2(res) res = func3(res) res = func4(res) print(res) #最終的な目標値
こんな感じである関数の戻り値を使って、次の関数の引数に何回も渡すことってわりとある気がします
ただ毎回resに戻り値いれて、次の関数の引数にいれてって単純にめんどくさいし、どこで何か起きてるのか後に分かりにくい
ただelixirにはパイプ演算子という強力な構文が用意されており、上記のようなことが簡単に行える
numbers = [1,2,3,4,5] res = Enum.map(numbers, fn ...) |> Enum.map(fn ...) |> Enum.map(fn ...) |> Enum.map(fn ...) IO.inspect(res)
まるで工場のベルトコンベアのように順を追うことができて何がしたいのかがパッと見れば分かる(川の様との意見も
実際に試してみた
最初はシンプルな問題に取り組んでみた
data: 1...100(range)
1. 全ての要素を8倍
2. 500以上の要素を削除
3. 残りの要素を足し合わせる
data = 1..100 data |> Enum.map(fn x -> x * 8 end) |> Enum.filter(fn x -> x <= 500 end) |> Enum.sum() #result: 15624
ここではelixirの文法を確認しつつも、特に詰まる部分はなかった
しかし、あえてsumを使わずにreduceを使って実装してみることに(マゾ
reduce使えばできることってだいたいEnumに実装されているのでreduceの活躍できる場所は中々難しいです
reduceの詳細は優しく分かるEnumのreduce関数と簡単なサンプルで解説しています
data = 1..100 data |> Enum.map(fn x -> x * 8 end) |> Enum.filter(fn x -> x <= 500 end) |> Enum.reduce(fn x, accum -> x + accum end) #result: 15624
提案を頂き、ついでにreduceで最大値も求めることに
data = 1..100 data |> Enum.map(fn x -> x * 8 end) |> Enum.filter(fn x -> x <= 500 end) |> Enum.reduce(fn x, accum -> if x < accum do accum else x end end) #result: 496
続いて文字列にチャレンジ
data = ["apple", "banana", "peach", "grape", "orange", "strberry", "pineapple", "raspberry"]
1. 頭文字を大文字にする
2. "a"を除去する
3. "py"を単語の最後に結合する
ここで初めてStirngモジュールが登場し全員で公式ドキュメントを漁る
先頭の文字列を大文字に変換してくれるString.capitalizeたるものを発見しアガる
data |> Enum.map(fn str -> String.capitalize(str) end) #result: # ["Apple", "Banana", "Peach", "Grape", "Orange", "Strberry", "Pineapple", "Raspberry"]
つづいて"a"を文字列から削除するが、空文字に置き換えてしまえばいいことに気づき再びアガる
data |> Enum.map(fn str -> String.capitalize(str) end) |> Enum.map(fn str -> String.replace(str, "a", "") end) #result: #["Apple", "Bnn", "Pech", "Grpe", "Ornge", "Strberry", "Pinepple", "Rspberry"]
ここで重要なことに気づく。Aが消えてねーじゃん!!!! なんで先に大文字に変換したねん〜
ゴリ押しで解決する
data |> Enum.map(fn str -> String.capitalize(str) end) |> Enum.map(fn str -> String.replace(str, "a", "") end) |> Enum.map(fn str -> String.replace(str, "A", "") end) #result: #["pple", "Bnn", "Pech", "Grpe", "Ornge", "Strberry", "Pinepple", "Rspberry"]
最後に文字列の連結演算子 "a "<> "b" = "ab" をつかって"py"を付与する
data |> Enum.map(fn str -> String.capitalize(str) end) |> Enum.map(fn str -> String.replace(str, "a", "") end) |> Enum.map(fn str -> String.replace(str, "A", "") end) |> Enum.map(fn str -> str <> "py" end) #result: #["pplepy", "Bnnpy", "Pechpy", "Grpepy", "Orngepy", "Strberrypy", "Pinepplepy", "Rspberrypy"]
1mmも意味のない単語が出来上がる...
残念ながら時間切れ
マップを使った問題に取り組み始めた所でレンタル会議室の時間切れ...
結局ここまでしか触れませんでした(反省
マップを触るには先にパターンマッチ知りたいねという話になり
次回はパターンマッチについて勉強しようと思います
今回の勉強会では記事にしてない部分を含めて
等を共有しました
ワイワイ楽しく出来たと思います
次回はまた2週間後(4月下旬)に開催予定です
よろしければぜひconnpassからご参加ください