Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm elixir中二维列表的置换_Algorithm_Elixir_Tail Recursion - Fatal编程技术网

Algorithm elixir中二维列表的置换

Algorithm elixir中二维列表的置换,algorithm,elixir,tail-recursion,Algorithm,Elixir,Tail Recursion,我试图使用一个简单的尾部递归来检索列表列表的所有排列。该模块如下所示: defmodule Permutations do def of([], accumulator) do accumulator end def of([head | tail], accumulator) do for item <- head, do: of(tail, accumulator ++ [item]) end end 不幸的是,当递归展开时,排列数组是嵌套的。该规

我试图使用一个简单的尾部递归来检索列表列表的所有排列。该模块如下所示:

defmodule Permutations do

  def of([], accumulator) do
    accumulator
  end

  def of([head | tail], accumulator) do
    for item <- head, do: of(tail, accumulator ++ [item])
  end
end
不幸的是,当递归展开时,排列数组是嵌套的。该规范的结果是:

    Expected `[[[[1, 1, 1], [1, 1, 2], [1, 1, 3]], [[1, 2, 1], [1, 2, 2],
[1, 2, 3]], [[1, 3, 1], [1, 3, 2], [1, 3, 3]]], [[[2, 1, 1], [2, 1, 2], 
[2, 1, 3]], [[2, 2, 1], [2, 2, 2], [2, 2, 3]], [[2, 3, 1], [2, 3, 2], 
[2, 3, 3]]], [[[3, 1, 1], [3, 1, 2], [3, 1, 3]], [[3, 2, 1], [3, 2, 2], 
[3, 2, 3]], [[3, 3, 1], [3, 3, 2], [3, 3, 3]]]]` to equals (==) 
`[[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 2, 1], [1, 2, 2], [1, 2, 3], 
[1, 3, 1], [1, 3, 2], [1, 3, 3], [2, 1, 1], [2, 1, 2], [2, 1, 3], 
[2, 2, 1], [2, 2, 2], [2, 2, 3], [2, 3, 1], [2, 3, 2], [2, 3, 3], 
[3, 1, 1], [3, 1, 2], [3, 1, 3], [3, 2, 1], [3, 2, 2], [3, 2, 3], 
[3, 3, 1], [3, 3, 2], [3, 3, 3]]`, but it doesn't.

如果有任何关于如何防止筑巢的建议,我将不胜感激。不幸的是,平坦化输出也删除了组合的一阶分组。

就我而言,最简单的方法是平坦化结果:

def flatten(list, acc \\ []) when is_list(list) do
  unless list |> Enum.all?(&is_list(&1)) do
    acc ++ [list]
  else
    list |> Enum.reduce(acc, fn e, acc -> acc ++ flatten(e) end)
  end
end
IO.inspect Permutations.of(list_list, []) |> Permutations.flatten
#⇒ desired
因为这不是标准的展平,所以它应该保持嵌套数组的-1级别。所有试图在运行中压平结果的尝试都会破坏尾部递归


另一种选择是使用
flat\u map
+
chunk

def of([head | tail], accumulator) do
  head |> Enum.flat_map(&of(tail, accumulator ++ [&1]))
end

IO.inspect Permutations.of(list_list, []) |> Enum.chunk(list_list |> Enum.count)
#⇒ desired

下面的解决方案有点不寻常

我看过你的代码,我记得列表可以用作Monad,通常Monad列表用于回溯。Elixir的语句以某种方式执行回溯:for语句。要解决您的问题,您可以执行以下操作:

for i <- [1,2,3], j <- [1,2,3], k <- [1,2,3], do: [i, j, k]

对于我,请共享一个
过程
函数。
for i <- [1,2,3], j <- [1,2,3], k <- [1,2,3], do: [i, j, k]
defmodule Permutation do
  @doc """
  Does the permutations over a list of lists.

  ```
  > require Permutation
  > Permutation.of([[1,2], [1,2]])
  [[1, 1], [1, 2], [2, 1], [2, 2]]
  ```
  """
  defmacro of(list) do
    quote do: unquote(gen(list))
  end

  ##
  # Generates the for statement for the permutation depending on
  # the contents of the input list. Starting index for generated 
  # variables is 0, there are no arrows and the initial result is
  # an empty list.
  @doc false
  def gen(list) do
    gen(list, 0, [], [])
  end

  ##
  # Generates the for statement for the permutation depending on
  # the contents of the input lists.
  defp gen([], _, arrows, list) do
    gen_for(arrows, list)
  end
  defp gen([head | tail], index, arrows, list) when is_list(head) do
    var = gen_var(index)
    arrow = gen_arrow(var, head)
    list = gen_list(var, list)
    gen(tail, index + 1, [arrow | arrows], list)
  end
  defp gen(_, _, _, _) do
    :error
  end

  ##
  # Generates a variable from an index i.e for index 0 generates i0
  defp gen_var(index), do: Macro.var(:"i#{inspect index}", __MODULE__)

  ##
  # Generates an arrow for the for statement i.e. i0 <- [1,2,3]
  defp gen_arrow(var, source) do
    quote do: unquote(var) <- unquote(source)
  end

  ##
  # Generates the list from the for statement block: [i1 | [i0]]
  defp gen_list(var, list) do
    quote do: [unquote(var) | unquote(list)]
  end

  ##
  # Generates the for statement i.e.
  # for i1 <- [1,2,3], i0 <- [1,2,3], do: [i1 | [i0]]
  defp gen_for(arrows, list) do
    quote do
      for unquote_splicing(arrows) do
        unquote(list)
      end
    end
  end
end