Разделить список на N частей - PullRequest
0 голосов
/ 15 мая 2018

Учитывая список, как я могу разделить его на N подсписков?Они не обязательно должны быть одинакового размера.Например, дали 9 элементов и разбили его на N = 3 подсписка => 3x3.Или в N = 4 подсписков => 2, 2, 2 и 1.

Как я могу это сделать?Разве в библиотеке Elixir нет функции?

Enum.split разбивает список на 2 части

update:

Если у меня есть 7 элементов, и я хочу их разделитьв 3 подсписка должно быть создано 3 подсписка:

[[3 elements], [2 elements], [2 elements]] 

А именно, я хочу сохранить все элементы

Ответы [ 2 ]

0 голосов
/ 15 мая 2018

Давайте предположим, что мы хотим 3 куска:

list = [1, 2, 3, 4, 5, 6, 7]
chunk_count = 3
chunk_length =
  list
  |> Enum.count()
  |> div(chunk_count)


list
|> Enum.with_index() # to calculate position
|> Enum.reduce(%{}, fn {e, i}, acc ->
     Map.update(acc, rem(div(i, chunk_length), chunk_count), [e], &([e | &1]))
   end)
|> Map.values()      # since we do need lists
|> Enum.map(&Enum.reverse/1)
#⇒ [[1, 2, 7], [3, 4], [5, 6]]

Если бы списки в Elixir должны были реализовывать поведение Access, код был бы намного проще, поскольку мы могли бы использовать Kernel.put_in/3.

0 голосов
/ 15 мая 2018

Можно использовать Enum.chunk_every, чтобы разбить список на подсписки из n элементов суммы каждый:

some_list = [1, 2, 3, 4, 5, 6]
Enum.chunk_every(some_list, 2)
[[1, 2], [3, 4], [5, 6]]

Путем вычисления общей длины списка сначала:

total_length = length(some_list)

и деление этого числа на желаемое количество частей, дающее вам длину каждого блока:

desired_amount_of_sublists = 3
chunk_length = Integer.floor_div(total_length, desired_amount_of_sublists)

должно позволить вам произвольно разделить список на столько частей, сколько вам нужно:

Enum.chunk_every(some_list, chunk_length)
[[1, 2], [3, 4], [5, 6]]

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

Enum.chunk_every([1,2,3,4,5,6,7], 2, 2, :discard)
[[1, 2], [3, 4], [5, 6]]

В случае, если у вас есть жесткое требование, когда вы не можете отказаться от какого-либо элемента, и, например, вам нужно, чтобы остальные элементы были включены в первый подсписок, вы можете сделать следующее:

Скажите, что с вышеприведенным вы получите:

result_so_far = Enum.chunk_every([1,2,3,4,5,6,7], 2)
[[1, 2], [3, 4], [5, 6], [7]]

Первый обратный result_so_far и возьмите первый его подсписок, который будет [7], следующим образом:

[last_sublist | other_sublists] = Enum.reverse(result_so_far)

Затем вы проверяете длину last_sublist.Если это соответствует chunk_length, то у вас все в порядке, result_so_far дает желаемый результат.В случае, если оно меньше chunk_length, вам нужно будет включить его элементы в первый подсписок result_so_far, который вы можете сделать следующим образом: [first_sublist | rest ] = Enum.reverse(other_sublists)

[Enum.concat(first_sublist, last_sublist) | rest] должен затем отобразить

[[1, 2, 7], [3, 4], [5, 6]]

...