Earlier this week, I wanted to render a list of items on a website in a grid of 3 columns per row. Typically, I'd resort to Tailwind's Grid to accomplish this, but I wanted to do it programmatically in Ruby. While trying to hack a solution with loops and conditions, I came across the each_slice method in Ruby.
The each_slice method breaks the list into multiple, smaller lists of a given size. Since it returns self enumerator, you'd call to_a on it to get the chunked list.
items = [1, 2, 3, 4, 5, 6, 7]
chunks = items.each_slice(4).to_a
# [[1, 2, 3, 4], [5, 6, 7]]Even better, since each_slice returns an enumerator, you can pass a block that operates on each chunk.
items = [1, 2, 3, 4, 5, 6, 7]
items.each_slice(4) { |chunk| pp chunk }
# [1, 2, 3, 4]
# [5, 6, 7]This method is especially useful in views when working with a grid system. For example, imagine you have a list of ActiveRecord models you want to display in a grid. Here's how you'd arrange that list into three columns per row.
<% products.each_slice(3) do |chunk| %>
<div class="row">
<% chunk.each do |product| %>
<div class="col-xs-4"><%= product.name %></div>
<% end %>
</div>
<% end %>It will render the grid in a 3-column structure.
Are you using Rails?
Use the in_groups_of method.
in_groups_of(number, fill_with = nil, &block)It splits or iterates over the array in groups of size number, padding any remaining slots with fill_with unless it is false.
%w(1 2 3 4 5 6 7 8 9 10).in_groups_of(3) {|group| p group}
["1", "2", "3"]
["4", "5", "6"]
["7", "8", "9"]
["10", nil, nil]
%w(1 2 3 4 5).in_groups_of(2, ' ') {|group| p group}
["1", "2"]
["3", "4"]
["5", " "]
%w(1 2 3 4 5).in_groups_of(2, false) {|group| p group}
["1", "2"]
["3", "4"]
["5"]Another excellent use case for chunking is when you have a large number of items to process and you want to do it on a group of items at a time. For example, you have a list of a million users and you want to process them 1000 at a time.
users.in_groups_of(1000, false) do |group|
# process the group of 1000 users
endIn fact, the in_groups_of method uses each_slice behind the scenes.
# active_support/core_ext/array/grouping.rb
def in_groups_of(number, fill_with = nil, &block)
if fill_with == false
collection = self
else
padding = (number - size % number) % number
collection = dup.concat(Array.new(padding, fill_with))
end
if block_given?
collection.each_slice(number, &block)
else
collection.each_slice(number).to_a
end
endI hope you liked this article and you learned something new.
As always, if you have any questions or feedback, didn't understand something, or found a mistake, please leave a comment below or send me an email. I look forward to hearing from you.
If you'd like to receive future articles directly in your email, please subscribe to my blog. If you're already a subscriber, thank you.