给定一个列表,如何将其拆分为N个子列表?他们不一定必须具有相同的规模。例如,给定9个元素并将其分成N = 3个子列表=> 3×3。或者进入N = 4个子列表=> 2,2,2和1。
我该怎么做? Elixir库中没有函数吗?
Enum.split
将列表拆分为2部分
更新
如果我有7个元素并且我想将它们分成3个子列表,那么应该创建3个子列表:
[[3 elements], [2 elements], [2 elements]]
即,我想保留所有元素
答案 0 :(得分:3)
您可以考虑使用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]]
答案 1 :(得分:0)
我们假设我们需要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
。
答案 2 :(得分:0)
找到了这个问题,但当前的答案都不适用于我的用例,为此,我希望组的大小尽可能一致。例如:
Enum.to_list(1..100) |> chunk_uniformly(6) |> Enum.map(&length/1)
# desired result is [17, 17, 17, 17, 16, 16]
# current accepted answer returns [20, 16, 16, 16, 16, 16]
这是我最终的解决方法:
def chunk_uniformly(list, number_of_chunks) do
len = length(list)
optimal_chunk_size = div(len + number_of_chunks - 1, number_of_chunks)
overspill = optimal_chunk_size * number_of_chunks - len
{full_chunks, partial_chunks} =
list
|> Enum.split((number_of_chunks - overspill) * optimal_chunk_size)
Enum.concat(
full_chunks |> Enum.chunk_every(optimal_chunk_size),
case partial_chunks do
[] -> List.duplicate([], overspill)
ls -> ls |> Enum.chunk_every(optimal_chunk_size - 1)
end
)
end
如果像在我的用例中那样,您实际上是在最大块大小的情况下工作的,则可以得到如下的块数:
number_of_chunks = div(length(list) + max_chunk_size - 1, max_chunk_size)