首页 > 解决方案 > 使用列表推导生成潜在组合

问题描述

我需要生成具有一些已确定值的系列数据集,以针对算法进行测试。数据样本数据看起来像["apple", "orange", "apple", nil, "pineapple", nil],我需要每个零点的苹果、橙子和菠萝的每种组合,例如在这种情况下,我需要一个列表列表

[
  ["apple", "orange", "apple", "apple", "pineapple", "apple"],
  ["apple", "orange", "apple", "orange", "pineapple", "apple"],
  ["apple", "orange", "apple", "pineapple", "pineapple", "apple"],
  ["apple", "orange", "apple", "apple", "pineapple", "orange"],
  ["apple", "orange", "apple", "orange", "pineapple", "orange"],
  ...
]

我目前正在尝试使用 List Comprehensions 的递归方法,但我们公司刚刚开始使用 Elixir,我还不熟悉它是如何组合在一起的。

我调用了这个方法generate_sample_data,它需要一个数据列表和一个累加器(列表列表)。

  def generate_sample_data(list, valid_lists \\ []) do
    case Enum.find_index(list, fn(f) -> f == nil end) do
      nil -> [list | valid_lists]
      index -> 
        for x <- ["apple", "orange", "pineapple"] do
          list
          |> List.update_at(index, fn(_)-> x end)
          |> Enum.each(&generate_sample_data/2)
        end
    end
  end

但我得到了错误#Function<4.433245229/2 in SampleData.generate_sample_data/2> with arity 2 called with 1 argument ("apple")

我不知道如何正确地将这些组合从列表理解转换为列表列表。无论我尝试什么似乎都会向我抛出不同的错误,但我觉得我有点接近了。

标签: elixir

解决方案


在您的特定情况下,问题在这里:

|> Enum.each(&generate_sample_data/2)

这是尝试调用generate_sample_data/2传递唯一参数(来自管道的列表。)

此外,Enum.each/2在那里没有任何意义,因为您基本上是在迭代上一步创建的有效列表的元素。

另一个潜在问题是nil -> [list | acc]您使用从未定义的acc局部变量的子句。


FWIW,这是产生初始列表的所有排列的宏:

defmacro permutations(l, n) do
  clause = fn i -> {:<-, [], [{:"i#{i}", [], Elixir}, l]} end
  return = Enum.map (1..n, fn i -> {:"i#{i}", [], Elixir} end)
  Enum.reduce(1..n, return, fn i, acc ->
    {:for, [], [clause.(i), [do: acc]]}
  end)
end

推荐阅读