问题
I'm trying to understand list comprehensions in Elixir.
The example I'm looking at is producing the permutations of a string from this answer.
def shuffle([], _), do: [[]]
def shuffle(_, 0), do: [[]]
def shuffle(list, i) do
for x <- list, y <- shuffle(list, i-1), do: [x|y]
end
How does this double-generator comprehension look when re-written without the comprehension? I made an attempt to implement the algorithm myself, but my implementation is appending to the list, rather than prepending as in the comprehension. I want to write the algorithm without the comprehension but with identical behaviour.
回答1:
A comprehension without filters can be converted into a sequence of Enum.flat_map
and Enum.map
. Specifically, all but the last one will become flat_map
and the last one will become map
. Here's a translation of your code:
list
|> Enum.flat_map(fn x ->
shuffle(list, i - 1)
|> Enum.map(fn y ->
[x | y]
end)
end)
I tested with A.shuffle([1, 2, 3, 4, 5], 2)
and the output looks identical to the original code in that question.
回答2:
Running Dogbert's example with the flat_map
replaced with map
really helped me see what was going on:
iex(1)> Permute.shuffle(~w(A B C), 3)
[
[
["A", ["A", ["A"]], ["A", ["B"]], ["A", ["C"]]],
["A", ["B", ["A"]], ["B", ["B"]], ["B", ["C"]]],
["A", ["C", ["A"]], ["C", ["B"]], ["C", ["C"]]]
],
[
["B", ["A", ["A"]], ["A", ["B"]], ["A", ["C"]]],
["B", ["B", ["A"]], ["B", ["B"]], ["B", ["C"]]],
["B", ["C", ["A"]], ["C", ["B"]], ["C", ["C"]]]
],
[
["C", ["A", ["A"]], ["A", ["B"]], ["A", ["C"]]],
["C", ["B", ["A"]], ["B", ["B"]], ["B", ["C"]]],
["C", ["C", ["A"]], ["C", ["B"]], ["C", ["C"]]]
]
]
来源:https://stackoverflow.com/questions/50653654/elixir-what-does-a-multiple-generator-list-comprehension-look-like-without-the