2017-03-30 66 views
1

我一直在摸索着這一段時間。我正在編寫一個程序,將給定文本文件中每個單詞的頻率輸出到.csv文件。我成功地創建了函數,可以查找每個單詞的頻率並將其結果作爲地圖輸出,但我的tocsv函數將結果寫爲流結果,出於某種原因,我無法弄清楚爲什麼,或者如何避免這種情況。這裏是我的代碼:Elixir:試圖將地圖寫入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功能,但有事在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.write/2寫入字節到設備上,而IO.inspect/3根據檢查的第二個參數給定的選項使用IO設備。另外,CSV.encode/1期望二維列表。這就是說

,你應該用IO.write/2堅持如本例中提到,在count產生2D列表,而一個Map

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 

在這樣一個簡單的例子,我只想使用裸藥劑產生一個文件,但(假設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--這是一個理想而又非常簡單的解決方案。我有一個雖然問題是,剛剛產生的CSV文件沒有任何休息concantenated在一起的所有數據,就像這樣: organism1run1ceiling1plagiarism1taking1test1sounds1sadness1freshness1deep1stairs1conformation1investment2 任何想法如何,我可以解決這個問題? –

+0

理想情況下,我希望將csv格式化,以便每個單詞及其頻率出現在同一行上,用製表符或逗號勾勒出頻率爲 –

+0

的單詞。請參閱更新。 ['Enum.join/2'](https://hexdocs.pm/elixir/Enum.html#join/2)可以指定'joiner'作爲第二個參數,並且結果與'「連接\ n 「'現在。 – mudasobwa