Let's say I want to get a certain number of even groups based on a collection of records with varying count. How is this possible?
I'm looking for a method like objects.in_x_even_groups(4)
Let's say I want to get a certain number of even groups based on a collection of records with varying count. How is this possible?
I'm looking for a method like objects.in_x_even_groups(4)
Group your objects by their index modulo the number of groups.
objects.group_by.with_index { |_, i| i % num_groups }.values
Example:
objects = %w{a b c d e f g h i j k}
objects.group_by.with_index { |_, i| i % 3 }.values
# [["a", "d", "g", "j"], ["b", "e", "h", "k"], ["c", "f", "i"]]
This won't pad undersized groups with nil and it also will interleave your objects. So this won't work if you need consecutive objects to be in the same group.
You are probably looking for the in_groups
method. From the docs:
in_groups(number, fill_with = nil)
Splits or iterates over the array in
number
of groups, padding any remaining slots withfill_with
unless it isfalse
.%w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group} ["1", "2", "3", "4"] ["5", "6", "7", nil] ["8", "9", "10", nil]
I assume:
l-s
is to be minimized, where l
is the size of the largest group and s
is the size of the smallest group; andl-s
will be at most 1
.
def group_em(arr, ngroups)
n_per_group, left_over = arr.size.divmod(ngroups)
cum_off = 0
ngroups.times.map do |i|
n = n_per_group + (i < left_over ? 1 : 0)
a = arr[cum_off, n]
cum_off += n
a
end
end
arr = [1, 2, 3, 4, 5, 6, 7]
(1..7).each { |m| puts "ngroups=#{m}: #{group_em(arr, m)}" }
ngroups=1: [[1, 2, 3, 4, 5, 6, 7]]
ngroups=2: [[1, 2, 3, 4], [5, 6, 7]]
ngroups=3: [[1, 2, 3], [4, 5], [6, 7]]
ngroups=4: [[1, 2], [3, 4], [5, 6], [7]]
ngroups=5: [[1, 2], [3, 4], [5], [6], [7]]
ngroups=6: [[1, 2], [3], [4], [5], [6], [7]]
ngroups=7: [[1], [2], [3], [4], [5], [6], [7]]
You're looking for in_groups_of
:
https://apidock.com/rails/Array/in_groups_of
array = %w(1 2 3 4 5 6 7 8 9 10)
array.in_groups_of(3) {|group| p group}
=>
["1", "2", "3"]
["4", "5", "6"]
["7", "8", "9"]
["10", nil, nil]