I have the following code that takes an array, and groups it by the sums of its elements:
class Array
def in_sums_of size, &block
block = -> el { el } unless block
container = []
each_with_index.inject([]) do |tmp, group|
element, idx = group
value = block.call(element)
sum = tmp.inject(0) { |sum,x| sum + block.call(x) }
if sum + value <= size
tmp << element
else
container << tmp if tmp.any?
tmp = [element]
end
container << tmp if idx == length - 1
tmp
end
container
end
end
[].in_sums_of(0)
# => []
[1].in_sums_of(1)
# => [[1]]
[1,1].in_sums_of(1)
# => [[1], [1]]
[1,1].in_sums_of(2)
# => [[1, 1]]
[3,2,1].in_sums_of(3)
# => [[3], [2, 1]]
[3,3].in_sums_of(3)
# => [[3], [3]]
[4,3,1].in_sums_of(3)
# => [[4], [3], [1]]
[{v: 1},{v: 2},{v: 2},{v: 3}].in_sums_of(3) do |el|
el[:v]
end
# => [[{:v=>1}, {:v=>2}], [{:v=>2}], [{:v=>3}]]
It takes an array and a limit, and puts elements into sub arrays, as long as there is space left, which is limited by size
var (3 in the example above).
The code works, and is already in production, but I was curious if this is the best approach. I haven't found a Rails helper or Ruby method that would help with this approach. So any ideas on this?
EDIT I've updated the code and added some examples.