やわらかテック

興味のあること。業務を通して得られた発見。個人的に試してみたことをアウトプットしています🍵

【レポート】第6回清流elixir勉強会inMisoca様を開催しました【競プロ@Elixir】

トピック

今回で第6回目の勉強会を開催致しました
elixir-sr.connpass.com

2019年4月から清流elixirの運営を初めて早2ヶ月
Elixirを全く知らない状態 & 新卒のクソザコでも何とかなりました
昨週、東京に行って感じたことは名古屋はまだ多くの技術がブルーオーシャン
connpass等での勉強会も開催されていないということ

Elixirは元々の知名度がアレですが、例えばReact専用の勉強会(nagoya.js的な)がなかったりして
先輩エンジニアから「名古屋でReactの勉強会あればねー」という話はよく耳にする
Haskel勉強会とかあったら普通に行きたい

こんな僕でも運営できているので、どなたでも始められると思います
自身で勉強会を運営すると顔が広くなっていろんな方と知り合えて
チャンスも生まれるし、強くなれます

本当にオススメです
なければ自分で作る。エンジニアの鑑ですね(唐突な自画自賛

また今回は開催場所に株式会社Misoca様のセミナールームを使用させて頂きました
めちゃ広くて快適な部屋を無料で使用させて頂きました
本当に有難うございます
地味にレンタルオフィスの料金が値上げしてるので非常に助かります

tech.misoca.jp

清流elixir-infomation
開催場所: 丸の内(愛知)
参加人数: 4 -> 3
コミュニティ参加人数 : 8 -> 10 update!!
20190607現在

第6回の活動内容

今まである程度、Elixirの文法の基礎部分は触ってきた
あとはElixirでの実装力を高めていき、サクサクとコードが書けるようになると良い
ということを常連参加者の方から提案があり、今回はAtCoderにある問題をElixirで解いてみることに

コードの成否判定には提案者の方が作ってきてくれたRailsのwebアプリを使った
はえーすっごい。感謝しかない。有難うございます

今回取り組んだ問題はこちらの2問

1問目

整数a,b,cと文字列sが与えられます。a+b+cの計算結果と文字列sを並べて表示する
PracticeA - Welcome to AtCoder
条件
- 1 ≤ a,b,c ≤1,000
- 1 ≤ |s| ≤ 100
入力例
1
2 3
test
出力例
6 test

2問目

1,2,3の番号のついて3つのマスからなるマス目があります。各マスには0か1が書かれています。
いくつの1があるか求めて下さい
条件
マスは必ず1か0
入力例
1000 出力例
1

Elixirでの標準入力の受け取り

これが結構難しい
以下の関数を使用することで受け取りが可能

IO.gets("")
iex(107)> IO.gets("")
111
"111\n"

しかし、このままだと改行記号である「\n」が含まれてしまうので除去したい

iex(108)> IO.gets("") |> String.trim()
111
"111"

任意の回数、入力を受け取りたい場合は自己流ですが以下を採用
第1問目が入力が3回固定なのでrangeで0..2を使っています

Stream.map(0..2, fn _ -> IO.gets("") end)
|> Stream.map(&(String.trim(&1)))
|> Stream.map(&(String.split(&1)))
|> Enum.to_list
|> List.flatten()
iex> Stream.map(0..2, fn _ -> IO.gets("") end)
|> Stream.map(&(String.trim(&1)))
|> Stream.map(&(String.split(&1)))
|> Enum.to_list
|> List.flatten()
1 2 3
4 5 6
test
["1", "2", "3", "4", "5", "6", "test"]

入力を受け取る準備が整ったので上記の2問に取り組んでみる
ちなみに、ここに到着するまで1時間ぐらいかかってしまった
競プロ経験の少なさを反省。かなり興味が湧いたので時間があればゆっくり取り組んでみたい

整数a,b,cと文字列sが与えられます。a+b+cの計算結果と文字列sを並べて表示する

先ほどの複数入力を使用する
まずは入力を受け取るところから

input_ = Stream.map(0..2, fn _ -> IO.gets("") end) |> Stream.map(&(String.trim(&1))) |> Stream.map(&(String.split(&1))) |> Enum.to_list |> List.flatten()
#input_ ["1", "2", "3", "4", "5", "6", "test"]

あとはシンプルで一番最後の値以外を取得して数値に変換して合計すれば良い
脳筋で問題を解くとこんな感じに落ち着いた

input_ = Stream.map(0..2, fn _ -> IO.gets("") end) |> Stream.map(&(String.trim(&1))) |> Stream.map(&(String.split(&1))) |> Enum.to_list |> List.flatten()
sum_ = Enum.take(input_, Enum.count(input_)-1) |> Enum.map(&(String.to_integer(&1))) |> Enum.sum()
str_ = Enum.at(input_, -1)
IO.puts("#{sum_} #{str_}")

#21 test

ブログではお見せできないが無事に全てのcaseでtrueになった

他の参加者の方からインスパイアを受けて2行にまで短縮することができた(パイプでつないでのは1行でカウント)
すごい。発想に脱帽

[str_ | nums] = Stream.map(0..2, fn _ -> IO.gets("") end) 
|> Stream.map(&(String.trim(&1))) 
|> Stream.map(&(String.split(&1))) 
|> Enum.to_list 
|> List.flatten() 
|> Enum.reverse()
IO.puts("#{Enum.sum(Enum.map(nums, &(String.to_integer(&1))))} #{str_}")

さらに突き詰めた結果、ワンライナーで書くことができた

with [str_ | nums] = Stream.map(0..2, fn _ -> IO.gets("") end) 
|> Stream.map(&(String.trim(&1))) 
|> Stream.map(&(String.split(&1))) 
|> Enum.to_list 
|> List.flatten() 
|> Enum.reverse(), do: 
IO.puts("#{Enum.map(nums, &(String.to_integer(&1))) |> Enum.sum()} #{str_}")

1,2,3の番号のついて3つのマスから...いくつの1があるか求めて下さい

こちらは入力が1つで固定なので先ほどより簡単
僕ですらワンライナーで書くことが何とかできた

Stringにクッソ便利なgraphemes()という関数が用意されており
文字列を(eg: "elixir")を1つ1つに分解してくれる(eg: ["e", "l", "i", "x", "i", "r"])
あとはこのリストから"1"以外(stringのまま)を除去してカウントすれば良い

IO.gets("") |> String.graphemes() |> Enum.filter(&(&1 == "1")) |> Enum.count() |> IO.puts()
IO.gets("") |> String.graphemes() |> Enum.filter(&(&1 == "1")) |> Enum.count() |> IO.puts()
101
2

やったぜ。
あれ、競プロっておもろい?

次回の告知

急ですが、来週(6/14(金))の19:30より福岡で活動されています
fukuoka.exさんのもくもく勉強会にリモートでジョインさせて頂くことになりました
fukuokaex.connpass.com

昨週に行ったErlang ElixirFest2019でお話を頂きまして光栄の限りです
開催場所がいつものレンタルオフィスではなく、名駅付近のレンタル会議室となりますのでご注意ください