Использование списочных представлений для генерации потенциальных комбинаций - PullRequest
0 голосов
/ 16 июня 2019

Мне нужно сгенерировать наборы данных серии с некоторыми уже определенными значениями для проверки алгоритма Данные выборки данных выглядят как ["apple", "orange", "apple", nil, "pineapple", nil], и мне нужно каждую комбинацию яблока, апельсина и ананаса для каждого нулевого пятна, например, в этом случае мне нужен список списков, который

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

В настоящее время я пробую рекурсивный подход с использованием списочных пониманий, но наша компания только начала использовать Elixir, и я еще не знаю, как все это объединяется.

У меня есть этот метод с именем generate_sample_data, который принимает список данных и аккумулятор (список списков).

  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

Но я получаю ошибку #Function<4.433245229/2 in SampleData.generate_sample_data/2> with arity 2 called with 1 argument ("apple")

Я не знаю, как правильно превратить эти комбинации из понимания списка в список списков. Все, что я пытаюсь сделать, кажется, вызывает у меня другую ошибку, но я чувствую, что я немного близок.

1 Ответ

1 голос
/ 16 июня 2019

В вашем конкретном случае проблема заключается в следующем:

|> Enum.each(&generate_sample_data/2)

Это попытка вызвать generate_sample_data/2, передавая единственный аргумент (список, полученный из канала.)

Кроме того, Enum.each/2 не имеет никакого смысла, потому что вы в основном перебираете элементы действительного списка, созданного на предыдущем шаге.

Другая потенциальная проблема может быть в предложении nil -> [list | acc], которое вы используетеникогда не определяется acc локальная переменная.


FWIW, вот макрос, который производит все перестановки исходного списка:

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
...