2017-03-30 13 views
1

私はしばらく頭を引っ張ってきました。私は与えられたテキストファイルのすべての単語の頻度を.csvファイルに出力するプログラムを作成しようとしています。私は各単語の頻度を見つけ出し、その結果を地図として出力する関数を作成することに成功しましたが、私のtocsv関数は何らかの理由で結果をストリーム結果として書きます。なぜかこれを避ける方法がわかりません。ここに私のコードは次のとおりです。エリクサー:CSVにマップを書き込もうとしましたが、ストリーム結果として書き込まれました

defmodule WordFrequency do 

    def wordCount(readFile) do 
    readFile 
    |> words 
    |> count 
    |> tocsv 
    end 

    defp words(file) do 
    file 
    |> File.stream! 
    |> Stream.map(&String.trim_trailing(&1)) 
    |> Stream.map(&String.split(&1,~r{[^A-Za-z0-9_]})) 
    |> Enum.to_list 
    |> List.flatten 

    end 

    defp count(words) when is_list(words) do 
    Enum.reduce(words, %{}, &update_count/2) 
    end 

    defp update_count(word, acc) do 
    Map.update acc, String.to_atom(word), 1, &(&1 + 1) 
    end 

    defp tocsv(map) do 
    file = File.open!("test.csv", [:write, :utf8]) 
    map 
    |> IO.inspect 
    |> Enum.map(&CSV.encode(&1)) 
    |> Enum.each(&IO.inspect(file, &1, [])) 
    end 

end 

数の結果は、(それがテストファイルです)、次のとおりです。

bitterness: 1, fan: 1, respiration: 1, radiator: 1, ceiling: 1, run: 1, 
    duck: 1, roundess: 1, terrorism: 1, she: 1, over: 1, equipment: 2, test: 1, 
    freshness: 1, feminism: 1, bucket: 1, goodness: 1, manliness: 1, 
    reflection: 1, uncomfortable: 1, tourism: 1, house: 1, ableism: 1, stairs: 1, 
    heroism: 1, sadness: 1, socialism: 1, fruit: 1, dogs: 1, mechanism: 1, 
    symbolism: 1, predilection: 1, up: 1, sedition: 1, faithfulness: 1, 
    fruition: 1, criticism: 1, conformation: 1, extradition: 1, braveness: 1, 
    ionization: 1, indigestion: 1, bubble: 1, introspection: 1, liquid: 1, 
    apartment: 1, deep: 1, department: 1, centralization: 1, bitter: 1, ...} 

は、だから、私は私のtocsv関数に流れを渡していないよということを知っているが、何かが起こりますこれをストリームに変換し、csvファイルに出力する前に書き込み可能な形式に変換しません。どのように私はこれに回避策を作ることができますか?私はこのCSVモジュールを使用しています:https://github.com/beatrichartz/csv

ありがとう!

答えて

3

使用CSVモジュールのREADMEでCSVを製造する例があります:

file = File.open!("test.csv", [:write, :utf8]) 
table_data |> CSV.encode |> Enum.each(&IO.write(file, &1)) 

IO.inspect/3はに従って第二引数を検査しながらIO.write/2は、デバイスへバイトを書き込むことに、注意してください指定されたオプションはIOデバイスを使用します。また、CSV.encode/1は、の2次元リストを想定しています。このような単純な場合には

defp count(words) when is_list(words) do 
    words 
    |> Enum.reduce(%{}, &update_count/2) 
    |> Enum.reduce([], fn {k, v}, acc -> [[k, v] | acc] end) 
end 

defp tocsv(map) do 
    file = File.open!("test.csv", [:write, :utf8]) 

    map 
    |> IO.inspect 
    |> CSV.encode 
    |> Enum.each(&IO.write(file, &1)) 
end 

、私は希望:Mapことではなく、おそらく例で述べたようにIO.write/2に固執し、countで2Dのリストを生成しなければならない、と述べた

countがあなたの元のコードのように、マップを返すと仮定)が、ファイルを生成するために裸エリクサーを使用します。

defp tocsv(map) do 
    File.open("test.csv", [:write, :utf8], fn(file) -> 
    Enum.each(map, &IO.write(file, Enum.join(Tuple.to_list(&1), ?,) <> "\n")) 
    end) 
end 

あるいは、さらに簡単:

defp tocsv(map) do 
    File.write!("test.csv", 
    map 
    |> Enum.map(Enum.join(Tuple.to_list(&1), ?,)) 
    |> Enum.join("\n")) 
end 
+0

ねえ、これは素晴らしい取り組んでいます!私は実際にElixirだけでcsvに書き込むことができないことを実感しました - これは理想的ではるかに単純な解決法です。 organism1run1ceiling1plagiarism1taking1test1sounds1sadness1freshness1deep1stairs1conformation1investment2 私はこの問題を解決することができますどのように任意のアイデア:私は持っています1つの問題は、生産csvファイルは、ちょうどこのような任意の休憩なしで一緒にconcantenatedすべてのデータを、持っているということでしょうか? –

+0

理想的には、CSVをフォーマットして、各単語とその頻度が1行に表示されるようにしたいのですが、周波数から単語を区切ったタブまたはコンマで –

+0

更新をご覧ください。 ['Enum.join/2'](https://hexdocs.pm/elixir/Enum.html#join/2)には、第二のパラメータとして' joiner'を指定するオプションがあり、その結果は '\ n "今、 – mudasobwa

関連する問題