githubの探検中に面白いものを見つける
なんだこれは(褒め言葉
Faker is a pure Elixir library for generating fake data.
fmfm...
どうやらフェイクデータを色々作れるライブラリだそうです
公式ドキュメントを見てみると
- 名前
- アドレス
- 地名
- ポケモン etc...
など様々なフェイクデータが用意されている模様
Fakerのインストール
今回は作成したデータのcsv出力までを行いたいのでついでにcsvもインストールしておく
いつも通りに新規プロジェクトを作成する
mix new create_fake
./create_fake/mix.exsのdepsに以下を追記
#この2つを追加 defp deps do [ {:faker, "~> 0.12"}, {:csv, "~> 2.3"}, ] end
いつも通りコマンドを叩き、外部ライブラリをダウンロードする
cd create_fake
mix deps.get
さらにtest/test_helper.exsに以下を追加
Faker.start()
これで準備は完了
とりあえずデータを作ってみる
まずは存在しない人間の情報を作ってみることにした
持たせる情報は
- 地域
- 名前(ファーストネームとラストネーム)
- 電話番号
- 好きな食べ物
- 年齢
上記の6つでマップ形式でサンプルデータを作成する
Faker
とErlang
モジュールの:rand
を使ってコードを書くとこんな感じに
iex> %{ email: Faker.Internet.email(), city: Faker.Address.En.city(), name: Faker.Name.En.first_name() <> " " <> Faker.Name.En.last_name(), phone: Faker.Phone.EnUs.phone(), food: Faker.Food.dish(), age: trunc(:rand.uniform() * 100) } %{ age: 26, city: "East Malachi", email: "dorcas1964@bergstrom.biz", food: "Fettuccine Alfredo", name: "Aniya Herzog", phone: "957/391-6739" }
うまく生成された
もう一度、実行してみると全く別のデータが作成された
%{ age: 39, city: "Nolan", email: "ashly.romaguera@johnson.org", food: "Chilli con carne", name: "Marta Yost", phone: "409.287.2291" }
このままだと単一のデータしか生成されないので
指定数分のデータをリストに格納して作成できるように変更
defmodule CreateMock do def user_info(num) do 1..num |> Enum.map(fn _ -> _user_info() end) end defp _user_info do %{ email: Faker.Internet.email(), city: Faker.Address.En.city(), name: Faker.Name.En.first_name() <> " " <> Faker.Name.En.last_name(), phone: Faker.Phone.EnUs.phone(), food: Faker.Food.dish(), age: trunc(:rand.uniform() * 100) #Erlangモジュールを使って乱数を生成 } end end
呼び出してみると良さげに生成されている
iex(11)> CreateMock.user_info(3) [ %{ age: 40, city: "Nicolas", email: "david2068@langosh.org", food: "Philadelphia maki", name: "Gwen Weber", phone: "930.422.1730" }, %{ age: 52, city: "Bayer", email: "yvonne2077@reynolds.biz", food: "Linguine with clams", name: "Favian Cummings", phone: "421/864-1117" }, %{ age: 86, city: "Haley", email: "gracie2021@hettinger.info", food: "Cheeseburger", name: "Margarette Ratke", phone: "(867) 614-8718" } ]
次にありそうなテストの成績データを生成してみる
持たせる情報は
- 名前
- 点数
- 科目名
の3つ
もう説明することは特にないのでコードと結果を先にお見せします
defmodule CreateMock do #デフォルトでmath(数学)を設定 def exam_info(num, subject \\ "math") do 1..num |> Enum.map(fn _ -> _exam_info(subject) end) end defp _exam_info(subject) do %{ name: Faker.Name.En.first_name() <> " " <> Faker.Name.En.last_name(), score: trunc(:rand.uniform() * 100), subject: subject } end end
iex(12)> CreateMock.exam_info(3) [ %{name: "General Wisoky", score: 55, subject: "math"}, %{name: "Alessia Cummings", score: 23, subject: "math"}, %{name: "Lilian Senger", score: 43, subject: "math"} ]
いいですね
フェイクデータの作成に関してはここで終了です
せっかくなのでcsvに書き出すことにします
生成したデータのcsvへの書き出し
生成したデータ(リストinマップ)の形式を
csvライブラリを使って書き出せるように指定形式の2次元のリストに変換します
ついでにheaderも挿入する
def output_data_to_csv(lst, header, file_name) do #ファイルを作成 file = File.open!(file_name <> ".csv", [:write, :utf8]) lst |> Enum.map(&(Enum.map(Map.to_list(&1), fn x -> {_, val} = x val end) )) |> List.insert_at(0, header) |> CSV.encode |> Enum.each(&IO.write(file, &1)) end
少しトリッキー(自称)なのはこの部分
Enum.map(&(Enum.map(Map.to_list(&1), fn x -> {_, val} = x val end) ))
まずは作成したデータをMap.to_list
を使ってまずはリスト形式に変換する
res = [ %{name: "Kennith Kling", score: 18, subject: "math"}, %{name: "Oliver O'Connell", score: 36, subject: "math"}, %{name: "Nicole Gutkowski", score: 6, subject: "math"}, %{name: "Blanche Deckow", score: 19, subject: "math"}, %{name: "Lysanne Gleichner", score: 62, subject: "math"}, ] iex> Enum.map(res, &(Map.to_list(&1))) [ [name: "Kennith Kling", score: 18, subject: "math"], [name: "Oliver O'Connell", score: 36, subject: "math"], [name: "Nicole Gutkowski", score: 6, subject: "math"], [name: "Blanche Deckow", score: 19, subject: "math"], [name: "Lysanne Gleichner", score: 62, subject: "math"], ]
このままだとkeyの値も含まれているため取り除きたい
data = [name: "Kennith Kling", score: 18, subject: "math"],
このデータに対してIO.inspectをそれぞれの要素に実行するとタプルになっていることが分かる
iex> Enum.map(data, &(IO.inspect(&1))) {name: "Kennith Kling"} {score: 18} {subject: "math}
なのでパターンマッチを使ってvalueのみを取り出す必要があり
こんなコードになったわけです
Enum.map(&(Enum.map(Map.to_list(&1), fn x -> {_, val} = x val end) ))
あとはcsvのドキュメントに従ってheaderを追加して書き出しているだけです
呼び出してみます
iex> fake_data = CreateMock.exam_info(20) iex> CreateMock.output_data_to_csv(fake_data, ["name", "score", "subject"], "score") :ok
無事にscore.csvが生成されました
name,score,subject Kennith Kling,18,math Oliver O'Connell,36,math Nicole Gutkowski,6,math : : Blanche Deckow,19,math
これうまく使えれば、勉強会とかでのデータ準備がめちゃくちゃ楽になりますね