Ruby Enumerable Module (Part 1)

Giulia Elizabeth
6 min readMay 12, 2021

--

https://www.pinterest.com/pin/801781539907236988/

In Ruby the Enumerable module is comprised of iteration methods. These perform search operations, sort operations, or check if a condition is met in a given collection.

In this article we split the methods into two groups Accessing & Interrogating, and Modifying & Grouping. Accessing & Interrogating include methods that read from the collection, and return piece of information from it (all, any, one, none, first, count, tally, entries, filter, find_all, select, find & find_index, grep, grep_v). Modifying & Grouping methods on the other hand group the collection based on a condition, or perform an operation on the elements of a collection (chain, drop, drop_while, take, take_while, collect, map, collect_concat, flat_map, each_entry, reverse_each, each_with_index, each_cons, each_slice, each_with_object, group_by, chunk, chunk_while).

Accessing & Interrogating Methods

  • all? Checks if all elements in a collection meet a given condition (block). If none of the collection members return false or nil enumerable will return true.
[1,5,6].all? { |num| num > 2} #=> false['1','5','6'].all? (String) #=> true['1','5', 6].all? (String) #=> false[nil, true, 99].all? #=> false[].all? #=> true
  • any? Checks if any element in a collection meets a given condition (block). If any of the elements return a value that is not false or nil, enumerable will return true.
[1, 5, 6].any? { |num| num > 2} #=> true[1, 5, 6].any? (Numeric) #=> true['1','5',6].any? (String) #=> true[nil, true, 99].any? #=> true[].any? #=> false
  • none? Checks if any element in a collection meets a given condition (block). Returns true if none of the elements return true, when passed through the block.
['1','5', 6].none? (String) #=> false(1..6).none? (String) #=> true
  • one? Checks if any element in a collection meets a given condition (block). Returns true if one of the elements return true, when passed through the block.
['1','5', 6].one? (String) #=> false[nil, false, 99].one? #=> true
  • include? returns true if any element in the collection is equal to the given argument (same as member?)
(1..6).include? 3
#=>true
(1..6).member? 3
#=>true
(1..6).member? 9
#=>false
  • count returns the number of elements that meet the condition. If no condition is given, returns total number of elements in group.
(1...6).count 
#=> 5
(1...6).count(&:even?)
#=> 2
  • tally returns a hash with the count for each element (ruby 2.7)
['bob','jim','jen','bob'].tally
#=> {'bob' => 2, 'jim' => 1, 'jen' => 1}
  • entries returns an array containing the elements in the given collection
(1..6).entries
#=>[1, 2, 3, 4, 5, 6]
{ 'cat'=>1, 'dog'=>2, 'penguin'=>3 }.entries
#=>[["cat", 1], ["dog", 2], ["penguin", 3]]
Prime.entries 5
#=>[2, 3, 5]
  • first returns the first or n elements in the given group
(1..6).first(3)
#=>[1, 2, 3]
{'a':1,'b':2,'c':3}.first(2)
#=>[[:a, 1], [:b, 2]]

Accessing & Interrogating (Search & Filter)

The below methods can be looked at as a subsection of Accessing & Interrogating, as they specifically search for elements, and filter out values.

  • grep returns an array of elements that match the given block
[5, 3, 4, 7, 2, 8, 3, 'bob'].grep 'bob'
#=>["bob"]
[5,3,4,7,2,8,3].grep 3..4
#=>[3, 4, 3]
  • grep_v returns an array of elements that do not match the given block
[5, 3, 4, 7, 2, 8, 3, 'bob'].grep_v 'bob'
#=>[5, 3, 4, 7, 2, 8, 3]
  • find returns the first element that meets the given condition, if there are no matches returns nil (same as detect)
(1..6).find(&:even?)
#=>2
(1...6).detect(&:even?)
#=> 2
  • find_index returns the index of the first element that meets the given condition, if there are no matches returns nil
(1..6).find_index(&:even?)
#=>1
  • filter iterates given collection and returns an array of all elements that return true for a given condition (same as find_all & select, filter_map is additionally available in Ruby 2.7)
(1..6).filter(&:even?)
#=>[2, 4, 6]
(1..6).filter{ |n| n > 2 }
#=>[3, 4, 5, 6]
(1..6).find_all{ |n| n > 2 }
#=>[3, 4, 5, 6]
(1..6).select{ |n| n > 2 }
#=>[3, 4, 5, 6]

Modifying & Grouping Methods

  • chain combines given collections into an Enumerable object
([1,5,6]).chain([1,2]).to_a #=> [1, 5, 6, 1, 2](1...6).chain([1,2]).to_a #=> [1, 2, 3, 4, 5, 1, 2]
  • take returns an array with the first n number of elements.
(1..6).take(2)
#=>[1, 2]
{'a':1,'b':2,'c':3}.take(2)
#=>[[:a, 1], [:b, 2]]
  • take_while returns an array with the first elements that meet the given condition
(1...6).take_while(&:even?)
#=>[]
(1...6).take_while(&:odd?)
#=> [1]
(1...6).take_while{ |n| n >= 1 }
#=>[1, 2, 3, 4, 5]
  • drop returns an array with the first n number of arguments removed.
(1…6).drop(2)
#=>[3, 4, 5]
{'a':1,'b':2,'c':3}.drop(1)
#=>[[:b, 2], [:c, 3]]
  • drop_while returns an array with the first elements that meet the given condition removed.
(1...6).drop_while{|n| n < 3}
#=> [3, 4, 5]
(1...6).drop_while(&:even?)
#=> [1, 2, 3, 4, 5]
([2, 5, 7, 9, 2]).drop_while(&:even?)
#=> [5, 7, 9, 2]
  • map runs a condition on every element in a given array, and returns a new array with the results (same as collect)
(1...6).collect {|n| n+1}
#=>[2, 3, 4, 5, 6]
(1...6).collect {|n| [n+1, 'bob']}
#=>[[2, "bob"], [3, "bob"], [4, "bob"], [5, "bob"], [6, "bob"]]
  • flat_map runs a condition on every element in a given array, and returns a concatenated array with the results (same as collect_concat)
(1...6).collect_concat {|n| [n+1, 'bob']}
#=>[2, "bob", 3, "bob", 4, "bob", 5, "bob", 6, "bob"]
(1..6).flat_map{|n| [n, 'number']}
#=>[1, "number", 2, "number", 3, "number", 4, "number", 5, "number", 6, "number"]
(1..6).collect_concat{|n| [n, 'number']}
#=>[1, "number", 2, "number", 3, "number", 4, "number", 5, "number", 6, "number"]
  • each_entry runs a condition on every element in a given array, and returns original array.
(1..6).each_entry{|n| p n+1}
#=> 2 3 4 5 6 7
=> 1..6
  • reverse_each runs a condition on every element in reverse order, and returns original array.
(1..6).reverse_each{|n| p n+1}
#=> 7 6 5 4 3 2
=> 1..6
  • each_with_index runs a condition (with access to the element’s index) on every element in a given array, and returns original array.
(1..6).each_with_index do |item, index| 
p [item, index]
end
#=>[1, 0] [2, 1] [3, 2] [4, 3] [5, 4] [6, 5]
  • each_cons runs a condition on every element in a given array, grouping together n elements.
(1..6).each_cons(3).to_a
#=>[[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]
  • each_slice performs the block (condition) on each ‘slice’ of the array
(1..6).each_slice(2).to_a
#=>[[1, 2], [3, 4], [5, 6]]
(1..6).each_slice(2) {|n| p n}
#=>[1, 2] [3, 4] [5, 6]
(1..10).each_slice(3).to_a
#=>[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
  • each_with_object iterates through array, and performs the block on each element. An object can be given, and block can be used to modify the given object.
(1..6).each_with_object(['numbers']){|num, arr| arr << num + 6 }
#=>["numbers", 7, 8, 9, 10, 11, 12]
  • group_by groups elements together based on the return of the given condition. Returns a hash where the keys are the results, and each value is an array of elements that matches that result
(1..6).group_by(&:even?)
#=>{false=>[1, 3, 5], true=>[2, 4, 6]}
  • chunk groups elements together based on the return of the given condition. Often used with .each method.
(1...6).chunk {|n| n.even?}.to_a 
or
(1...6).chunk(&:even?).to_a
#=>[[false, [1]], [true, [2]], [false, [3]], [true, [4]], [false, [5]]][1, 2, 4, 5, 6, 8, 8].chunk {|n| n.even?}.to_a
or
[1, 2, 4, 5, 6, 8, 8].chunk(&:even?).to_a
#=>[[false, [1]], [true, [2, 4]], [false, [5]], [true, [6, 8, 8]]][1, 2, 4, 5, 6, 8, 8].chunk(&:itself).to_a
#=> [[1, [1]], [2, [2]], [4, [4]], [5, [5]], [6, [6]], [8, [8, 8]]]
  • chunk_while groups elements together based on the return of the given condition. Additionally has the ability to compare adjacent elements in the given group, and run the condition on the element comparison.
(1...6).chunk_while {|n| n.even?}.to_a
#=> [[1], [2, 3], [4, 5]]
(1...6).chunk_while {|prev, current| prev+1 == current}.to_a
#=> [[1, 2, 3, 4, 5]]
([6,2,3,5,1,7,2]).chunk_while {|prev, current| prev > current}.to_a
#=> [[6, 2], [3], [5, 1], [7, 2]]

Part 2 will include to_a, to_h, uniq, inject, lazy, max, max_by, min, min_by, minmax, minmax_by, partition, reduce, reject, slice_after, slice_before, slice_when, sort, sort_by, sum, zip

https://ruby-doc.org/core-3.0.1/Enumerable.html

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

No responses yet

Write a response