Elixir: What does a multiple-generator list compre

2019-08-22 06:52发布

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.

2条回答
贼婆χ
2楼-- · 2019-08-22 07:25

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.

查看更多
成全新的幸福
3楼-- · 2019-08-22 07:25

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"]]]
  ]
]
查看更多
登录 后发表回答