首页 > 解决方案 > 迭代 Elixir 中的嵌套列表

问题描述

我试图解决这个问题很长一段时间,只有我发现的解决方案真的很难看。必须有更好的方法来解决这个问题:

给定配置

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

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

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

所以基本上是一个将原始配置转换为这个的函数:

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)

标签: elixir

解决方案


欢迎来到堆栈溢出!

对于初学者来说,是一种不可变的函数式语言,因此您可能熟悉的基于的常见“循环”概念在这里并不适用。但当然,您仍然可以以其他方式迭代数据集合,包括、each/2和推导 map/2reduce/4

如果您只是想打印每个项目的结果或在迭代中触发一次性事件而不返回任何内容,each/2这是最简单的选择,否则您最好使用map/2orreduce/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

根据您想要的输出方式进行一些小的更改后,您可以这样调用它:

TaskList.process_all(my_tasks, 2)

推荐阅读