Functional programming 在Elixir中打开并从多个文件中收集数据

Functional programming 在Elixir中打开并从多个文件中收集数据,functional-programming,stream,elixir,Functional Programming,Stream,Elixir,我在为我的研究自学长生不老药,通常我的研究需要打开几十个或几百个文本文件,将这些文件中的数据合并,并对数据进行处理。我试图弄清楚如何打开目录中的所有文件并访问所有这些文件中的数据。我希望避免使用for循环,因为在循环中迭代100个文件会非常慢。我认为流模块对于我来说是理想的,但我不知道如何使用它 下面,我有一些测试代码。它所要做的就是打开一堆包含随机数的文件,将文件中的数字字符串转换为整数,并对它们进行排序。除了“打开文件”部分,所有操作都正常。您可以看到,我尝试使用Path模块,这确实成功地找

我在为我的研究自学长生不老药,通常我的研究需要打开几十个或几百个文本文件,将这些文件中的数据合并,并对数据进行处理。我试图弄清楚如何打开目录中的所有文件并访问所有这些文件中的数据。我希望避免使用for循环,因为在循环中迭代100个文件会非常慢。我认为流模块对于我来说是理想的,但我不知道如何使用它

下面,我有一些测试代码。它所要做的就是打开一堆包含随机数的文件,将文件中的数字字符串转换为整数,并对它们进行排序。除了“打开文件”部分,所有操作都正常。您可以看到,我尝试使用Path模块,这确实成功地找到了所有文件,但我不知道如何以可用的方式将其传递给sort_num函数。谢谢大家的帮助

defmodule OpenFiles do

  def file_open do
    Path.wildcard("numfiles/*.txt")
  end

  def sort_num do
    file_open
    |> File.stream!
    |> Stream.map(&String.strip/1)
    |> Stream.map(&String.to_integer/1)
    |> Enum.sort
  end 
end

IO.inspect OpenFiles.sort_num

File.stream/3
功能一次只能处理一个文件。如果您使用通配符并同时收集多个文件,则它的工作方式与您预期的不同

如果查看
Path.wildcard/2
的返回,则会得到所有匹配文件的列表。类似于

["foo.txt", "bar.txt", "baz.txt"]
如果您将其传递到
File.stream/3
,它尝试将所有这些值附加在一起

File.stream! ["foo.txt", "bar.txt", "baz.txt"]
%File.Stream{line_or_bytes: :line, modes: [:raw, :read_ahead, :binary],
 path: "foo.txtbar.txtbaz.txt", raw: true}
如您所见,它认为您试图访问的路径是
“foo.txtbar.txtbaz.txt”
,这是不正确的,所有的“路径”都连接在一起

File.stream! ["foo.txt", "bar.txt", "baz.txt"]
%File.Stream{line_or_bytes: :line, modes: [:raw, :read_ahead, :binary],
 path: "foo.txtbar.txtbaz.txt", raw: true}
为了访问所有这些文件,您必须单独运行每个文件

defmodule OpenFiles do
  def file_open do
    Path.wildcard("numfiles/*.txt")
  end

  def sort_num do
    file_open()
    |> Enum.map(fn file ->
      file
      |> File.stream!()
      |> Stream.map(&String.strip/1)
      |> Stream.map(&String.to_integer/1)
      |> Enum.take(1) # This only takes the first line. This may or may not be what you want.
    end)
    |> List.flatten()
    |> Enum.sort()
  end 
end

正如您提到的,如果您有很多文件(或大文件),这可能需要很长时间。但是,您可以通过使用并行映射实现而不是顺序的
Enum.map/2

来缓解这一问题,这真是一个非常棒和详细的答案!非常感谢。是的,我认为并行映射实现将是我的最佳选择。