遍历Elixir中的嵌套列表

时间:2018-11-11 14:33:08

标签: elixir

我试图解决这个问题已经有一段时间了,只有我发现的解决方案真的很丑。必须有更好的方法来解决此问题:

给出配置

iterations = 2
tasklist = [
  {:system, print: "sth"},
  {:system, loop: [
    {:device1, run: "cmd" },
    {:device2, run: "cmd" },
  ], iterations: 3},
  {:device3, run: "cmd" },
]

配置从上到下进行处理,除{:system, loop: []}之外,每个命令都会打印一些结果(输出到CSV文件)。命令定义是不同的,并且可以包括范围作为输入值。

我想创建一个函数,该函数可以通过将配置扩展到没有循环和迭代的新步骤列表,而将信息保留在每个步骤中来实现嵌套循环。因此,如果步骤的输入值是范围,则该软件能够从步骤中提取总迭代次数和当前迭代次数,并使用它来进行其他一些计算。

因此基本上是一个将原始配置转换为此的功能:

tasklist = [
  {:system, print: "sth",mainiteration: 1, maintotalit: 2},
  {:device1, run: "cmd" ,loopiteration: 1, looptotalit: 3},
  {:device2, run: "cmd" ,loopiteration: 1, looptotalit: 3},
  {:device3, run: "cmd" ,mainiteration: 1, maintotalit: 2},

  {:system, print: "sth",mainiteration: 1, maintotalit: 2},
  {:device1, run: "cmd" ,loopiteration: 2, looptotalit: 3},
  {:device2, run: "cmd" ,loopiteration: 2, looptotalit: 3},
  {:device3, run: "cmd" ,mainiteration: 1, maintotalit: 2},

  {:system, print: "sth",mainiteration: 1, maintotalit: 2},
  {:device1, run: "cmd" ,loopiteration: 3, looptotalit: 3},
  {:device2, run: "cmd" ,loopiteration: 3, looptotalit: 3},
  {:device3, run: "cmd" ,mainiteration: 1, maintotalit: 2},

  {:system, print: "sth",mainiteration: 2, maintotalit: 2},
  {:device1, run: "cmd" ,loopiteration: 1, looptotalit: 3},
  {:device2, run: "cmd" ,loopiteration: 1, looptotalit: 3},
  {:device3, run: "cmd" ,mainiteration: 2, maintotalit: 2},

  {:system, print: "sth",mainiteration: 2, maintotalit: 2},
  {:device1, run: "cmd" ,loopiteration: 2, looptotalit: 3},
  {:device2, run: "cmd" ,loopiteration: 2, looptotalit: 3},
  {:device3, run: "cmd" ,mainiteration: 2, maintotalit: 2},

  {:system, print: "sth",mainiteration: 2, maintotalit: 2},
  {:device1, run: "cmd" ,loopiteration: 3, looptotalit: 3},
  {:device2, run: "cmd" ,loopiteration: 3, looptotalit: 3},
  {:device3, run: "cmd" ,mainiteration: 2, maintotalit: 2},
]

通过配置步骤的当前代码为:

Enum.each(1..iterations, fn n ->  
  Enum.each(tasklist, fn task ->
     IO.inspect(task) # My custom implementation
  end)
end)

2 个答案:

答案 0 :(得分:2)

欢迎堆栈溢出!

对于初学者来说,是一种不可变的功能语言,因此您可能熟悉的基于的常见“循环”概念在这里并没有真正应用。但是当然,您仍然可以通过其他方式遍历数据集合,包括each/2map/2reduce/4comprehensions

如果您只想打印每个项目的结果或在迭代中触发一次事件而不返回任何内容,则each/2是最简单的选择,否则最好使用{{1} }或map/2


解决您的实际问题,您可以通过使用功能子句中的模式匹配和递归在模块中处理任务列表中的每种情况来实现这一目标:

reduce/3

根据您希望的输出方式进行一些细微更改后,您可以按以下方式调用它:

defmodule TaskList do
  def handle({:system, print: message}) do
    IO.puts(message)
  end

  def handle({:system, loop: tasks, iterations: count}) do
    Enum.each(1..count, fn _ ->
      Enum.each(tasks, &handle/1)
    end)
  end

  def handle({device, run: command}) do
    # Call your command on the device
    # (Replace with your own implementation)
  end

  def handle(unknown) do
    # Do nothing or handle unexpected situations here
  end

  def process_all(tasks, iterations) when is_list(tasks) do
    handle({:system, loop: tasks, iterations: iterations})
  end
end

答案 1 :(得分:0)

好,所以原来的问题太复杂了,无法用这种方式解决...我们决定不像描述的那样集成嵌套列表选项,而只在其余软件的顶部集成一个初始化部分。因此,最终代码看起来像这样,仅供记录:

initit = 3
initlist = 
  [
    {:system, print: 10..15, header: "\tInitHeader1"},
  ]

mainit = 2
tasklist =
  [
    {:system, print: 1..5, header: "\tMainTaskHeader1"},
    {:system, print: 2..10, header: "\tMainTaskHeader2"}
  ]

Enum.each(1..initit, fn i ->
    Enum.each(1..mainit, fn t ->

      Enum.each(initlist, fn task ->
        runTask(task, initit, i)
      end)

      Enum.each(tasklist, fn task ->
        runTask(task, mainit, t)
      end)

    end)
  end)

非常感谢所有人。