coconutcrab
coconutcrab

Reputation: 131

Using List Comprehensions to generate potential combinations

I need to generate sets of series data with some already-determined values to test against an algorithm. The data sample data looks like ["apple", "orange", "apple", nil, "pineapple", nil] and I need to every combination of apple, orange, and pineapple for each nil spot, for example in this case I need a list of lists that is

[
  ["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"],
  ...
]

I am currently trying a recursive approach using List Comprehensions, but our company just started using Elixir, and I'm not yet familiar with how it all comes together.

I have this method called generate_sample_data that takes a list of data and an accumulator (list of lists).

  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

But I get the error #Function<4.433245229/2 in SampleData.generate_sample_data/2> with arity 2 called with 1 argument ("apple")

I don't know how to correctly turn these combinations from the list comprehension into a list of lists. Whatever I try seems to throw a different error at me, but I feel like I'm somewhat close.

Upvotes: 0

Views: 345

Answers (1)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

In your particular case, the issue is here:

|> Enum.each(&generate_sample_data/2)

This is an attempt to call generate_sample_data/2 passing the only argument (the list that comes from the pipe.)

Also, Enum.each/2 does not make any sense there, because you are basically iterating over the elements of the valid list created on the previous step.

Another potential issue would be in the clause nil -> [list | acc] you use never defined acc local variable.


FWIW, here is the macro that produces all the permutations of the initial list:

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

Upvotes: 1

Related Questions