如何在Elixir中获取列表的排列?
例如,对于["a", "b", "c"]
,我希望:
# [["a", "b", "c"], ["a", "c", "b"],
# ["b", "a", "c"], ["b", "c", "a"],
# ["c", "a", "b"], ["c", "b", "a"]]
答案 0 :(得分:9)
像这样:
defmodule Permutations do
def of([]) do
[[]]
end
def of(list) do
for h <- list, t <- of(list -- [h]), do: [h | t]
end
end
答案 1 :(得分:5)
方法略有不同,它还支持为结果列表指定所需的长度:
defmodule Permutations do
def shuffle(list), do: shuffle(list, length(list))
def shuffle([], _), do: [[]]
def shuffle(_, 0), do: [[]]
def shuffle(list, i) do
for x <- list, y <- shuffle(list, i-1), do: [x|y]
end
end
运行:
iex(24)> Permutations.shuffle ["a", "b", "c"]
[["a", "a", "a"], ["a", "a", "b"], ["a", "a", "c"], ["a", "b", "a"],
["a", "b", "b"], ["a", "b", "c"], ["a", "c", "a"], ["a", "c", "b"],
["a", "c", "c"], ["b", "a", "a"], ["b", "a", "b"], ["b", "a", "c"],
["b", "b", "a"], ["b", "b", "b"], ["b", "b", "c"], ["b", "c", "a"],
["b", "c", "b"], ["b", "c", "c"], ["c", "a", "a"], ["c", "a", "b"],
["c", "a", "c"], ["c", "b", "a"], ["c", "b", "b"], ["c", "b", "c"],
["c", "c", "a"], ["c", "c", "b"], ["c", "c", "c"]]
iex(25)> Permutations.shuffle ["a", "b", "c"], 2
[["a", "a"], ["a", "b"], ["a", "c"], ["b", "a"], ["b", "b"], ["b", "c"],
["c", "a"], ["c", "b"], ["c", "c"]]
答案 2 :(得分:0)
这是一个没有理解的版本:
defmodule Permute do
def permute(_chars, building, 0) do
[building]
end
def permute(chars, building, dec) do
Stream.map(chars, fn char -> building ++ [char] end)
|> Enum.flat_map(fn building -> permute(chars, building, dec - 1) end)
end
end
有一个帮助函数允许输入作为字符串也很有用:
def permute(str) do
permute(String.split(str, "", trim: true), [], String.length(str))
end
答案 3 :(得分:0)
为了便于发现,我将这段代码放在这里。
defmodule P do
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
end
defmodule T do
require P
def permute3(list), do: P.permutations(list, 3)
end
它使用普通AST返回嵌套列表推导。
T.permute3 ~w|a b|
#⇒ [
# [[["a", "a", "a"], ["b", "a", "a"]],
# [["a", "b", "a"], ["b", "b", "a"]]],
# [[["a", "a", "b"], ["b", "a", "b"]],
# [["a", "b", "b"], ["b", "b", "b"]]]
# ]
由于n
的早期扩展,需要花更多的精力才能使Range
作为参数传递,但仍然可行。
答案 4 :(得分:0)
我(重新)写了这篇文章,以更好地理解上面的答案:
def permutations(list) do
if list == [] do
[[]]
else
# recursively call itself on every element picked on the list and the remaining ones
for h <- list, t <- permutations(list -- [h]) do
[h | t]
end
end
end
它通过递归工作,如果列表为空,则返回仅包含空列表(空列表的唯一可能排列)的列表。
如果列表不为空,则迭代列表的每个元素h
并使用其余元素进行调用。然后,为每个结果构建连接列表。
让我有些困惑的是Elixir评估多个范围的for
的方式,我在official documentation中找不到它,但是似乎它评估了第一个值,结果可以在第二个中使用。例如,这是有效的:
for a <-1..3, b <- 1..a*2 do
"#{a} - #{b}"
end```