Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Split a list into N parts

Tags:

elixir

Given a list, how can I split it into N sub-lists? They don't have necessarily have to be of the equal size. For instance, given 9 elements and split it into N = 3 sub-lists => 3x3. Or into N = 4 sub-lists => 2, 2, 2 and 1.

How can I do that? Isn't there a function in Elixir library?

Enum.split splits a list into 2 parts

update:

If I have 7 elements and I want to split them into 3 sub-lists, there should be created 3 sublists:

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

Namely, I want to preserve all the elements

like image 681
Ivanari Avatar asked Mar 07 '23 05:03

Ivanari


1 Answers

You could consider using Enum.chunk_every to split the list into sublists of n amount elements each:

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

By calculating the total length of the list first:

total_length = length(some_list)

and dividing that number with the desired amount of parts giving you the length of each chunk:

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

should allow you to arbitrarily chunk the list into as many parts you require:

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

In the case that you have a hard requirement to have each sublist be of exactly n elements, then you can pass in the option :discard to discard the last sublist if it is less than n elements:

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

In the case that you have the hard requirement where you cannot discard any element and for instance you need the remainder elements to be incorporated with the first sublist, then you can do as follows:

Say that with the above you arrive at:

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

First reverse result_so_far, and take the first sublist thereof, which would be [7], as follows:

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

Then you check the length of last_sublist. If it corresponds to chunk_length, then you are fine, result_so_far has the desired result. In the case it is smaller than chunk_length, you will need to incorporate its elements with the first sublist of result_so_far, which you can do as follows: [first_sublist | rest ] = Enum.reverse(other_sublists)

[Enum.concat(first_sublist, last_sublist) | rest] should then render

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

like image 119
Kevin Johnson Avatar answered May 14 '23 07:05

Kevin Johnson