Sheharyar
Sheharyar

Reputation: 75740

Split list in two equal halves (±1)

I know I can split an even list in two equal halves in elixir by doing this:

list = [1, 2, 3, 4, 5, 6]
len = round(length(list) / 2)

[a, b] = Enum.chunk(list, len)            # => [[1, 2, 3], [4, 5, 6]]

but is there a ruby-esque method built-in or some more efficient way of doing this that also handles odd-length lists?

Upvotes: 8

Views: 5578

Answers (3)

Sheharyar
Sheharyar

Reputation: 75740

After going through the docs, and searching elsewhere I still didn't find a built in solution, but I did come across Enum.split/2. This method seems like a better fit to divide odd-length lists but returns a tuple instead of a list of lists.

I still don't know how efficient this is.

Example:

def split(list) do
  len = round(length(list)/2)
  Enum.split(list, len)
end


split([1, 2, 3, 4])        # => {[1, 2], [3, 4]}
split([5, 6, 7, 8, 9])     # => {[5, 6, 7], [8, 9]}

Upvotes: 5

Gazler
Gazler

Reputation: 84140

Enum.chunk_every/4 actually takes 4 arguments and will work with an odd length list if you include the 4th (pad) argument:

iex(14)> Enum.chunk_every([1,2,3,4,5], 3, 3, [])
[[1, 2, 3], [4, 5]]

Upvotes: 10

Onorio Catenacci
Onorio Catenacci

Reputation: 15293

I don't believe there is any "more idiomatic" way to do this. I don't know of a built-in method to do this.

One suggestion--if you're dealing with larger lists, you may be better off to use a Stream rather than an Enum.

list = [1,2,3,4,5,6,7,8,9]
s = Stream.take_every(list,2)
l2 = Enum.to_list(s)  #=> [1,3,5,7,9]

And then

l1 = list -- l2 #=> [2,4,6,8]

You're better off to use a Stream where you can because a Stream is lazily evaluated. In this particular case, it wouldn't make a difference. But in some cases lazy evaluation can really speed things up.

As I say my code is no more idiomatic than your solution and it's certainly not a built-in function.

Upvotes: 2

Related Questions