我需要解析大量的csv数据,其中文件的第一行是标题.该库:csv已经为我提供了一个列表流,我需要从第一行推断出结构但忽略它,然后生成具有给定结构的地图流.
我喜欢这个:
data.csv
a,b
1,2
3,4
...
Run Code Online (Sandbox Code Playgroud)
CSV.stream_map(filename)输出
{a: 1, b: 2} #1
{a: 3, b: 4} #2
...
Run Code Online (Sandbox Code Playgroud)
我正在调查,Stream.transform但无法弄清楚如何跳过第一个元素.结构可以存储在累加器中.
如果您headers: true作为第二个参数传递CSV.decode/2(如文档中所述),它将自动使用第一行作为键名,并为以下所有行返回Map.
iex(1)> CSV.decode(File.stream!("data.csv"), headers: true) |> Enum.to_list
[%{"a" => "1", "b" => "2"}, %{"a" => "3", "b" => "4"}]
Run Code Online (Sandbox Code Playgroud)
data.csv 包含:
a,b
1,2
3,4
Run Code Online (Sandbox Code Playgroud)
虽然正如我所发现的那样,该csv模块已经做到了这一点,但我也找到了一种自己实现这一点的方法。事实证明,如果您[]在Stream.transform回调中发回一个空列表,则不会将任何元素推入流中:
def map_stream(enum) do
enum
|> Stream.transform(:first, &structure_from_header/2)
end
#The accumulator starts as :first, the its the structure of the csv
#that is the first line
def structure_from_header(line, :first),
do: { [ ], line } #<=================== Here is the trick
def structure_from_header(line, structure) do
map =
structure
|> Enum.zip(line)
|> Enum.into(%{})
{ [ map ], structure }
end
Run Code Online (Sandbox Code Playgroud)