Aaron Rustad
Aaron Rustad

Reputation: 2026

Efficient approach to distributing elements of an array into chunks

Given an array of length N, how I can I equally distribute the elements of the array into another array of arbitrary length?

For instance, I have 3 items in an array and I'd like it distributed evenly across another array of 9 slots.

[1, 2, 3]

should result in (something close to)

[[], [], [1], [], [], [2], [], [], [3]]

However, if I have 9 items to distribute to an array length of 2, it should result in

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

Thanks!

NOTE: The position of the resulting array items could differ according to the algorithm, but the intent is to get some level of uniform distribution. In the first example, the 0th item could be [1]. In the second example, the 0th item could have [1,2,3,4,5].

Upvotes: 0

Views: 140

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110725

Here's an easy way to do that:

def distribute(arr, slots)
  n = arr.size
  a = Array.new(slots) { [] }
  arr.each_with_index { |e,i| a[i*slots/n] << e }
  a
end

distribute([1,2,3], 9)
  #=> [[1], [], [], [2], [], [], [3], [], []]
distribute([*(1..9)], 2)
  #=> [[1, 2, 3, 4, 5], [6, 7, 8, 9]]

You could change the distributions that result by modifying i*slots/n.

Upvotes: 2

Anthony
Anthony

Reputation: 15967

So there are two totally different use cases here, one where you have to build an array of length n, the other where you need to split into an array of length n.

This feels like a homework assignment but I don't really have enough off these two use cases to see a pattern (unless I'm missing something huge).

Test cases:

it 'splits on n vals' do
    arr = [1,2,3]
    expect(chunk(arr, 9)).to eq [[], [], [1], [], [], [2], [], [], [3]]
  end

  it 'splits on n vals' do
    arr = [1,2,3,4,5,6,7,8,9]
    expect(chunk(arr,2)).to eq [[1,2,3,4,5],[6,7,8,9]]
  end

Code:

def chunk(arr, num)
  if num < arr.length
    return arr.each_slice( (arr.size/num.to_f).round).to_a
  end
  array = []
  len = arr.length
  (0..num).each do |i|
    if (i % len == 0) && i != 0
      array[i-1] = [arr.first]
      array[i] = []
      arr.shift
    else
      array[i] =  []
    end
  end
  array.pop
  array
end

Upvotes: 1

Related Questions