DEV Community

Alexa Anderson
Alexa Anderson

Posted on • Edited on

Ruby's Enumerable Module

One of the most useful built-in modules is ruby's Enumerable. While it may invoke an eye-roll during an algorithmic tech screen, on the job, these functions are found in most, if not all, codeblocks involving Arrays or Hashes.

Here's a definitive view of Enumerable with examples.

# Module Enumerable

## Method: Each

#### The enumerable module requires the including or extending class define a `.each` method.
#### This method is expected to yield successive elements to the calling block.
#### This method is used as an implementation detail of most Enumerable methods.

items = ['this', 'thing', 'the', 'other', 'thing']

### Call a block with each successive element
items.each { |i| print i } # prints "this" then prints "thing" then prints "the" then prints "other" then prints "thing"
Enter fullscreen mode Exit fullscreen mode

This interactive Ruby Environment is available for hands-on practice with Enumerable:


items = ['this', 'thing', 'the', 'other', 'thing']

## Querying: Return information

### Check for inclusion
items.member? 'this' # true
items.member? 'grape' # false
items.include? 'this' # true
items.include? 'grape' # false

### Check for omnipresence
items.all? { |i| i.class === String } # true
items.all? { |i| i === 'this' } # false

### Check for at least one
items.any? { |i| i.class === String } # true
items.any? { |i| i === 'grape' } # false

### Check for anti-presence
items.none? { |i| i.class === Integer } # true
items.none? { |i| i.class === String } # false

### Check for exactly one
items.one? { |i| i === 'this' } # true
items.one? { |i| i === 'thing' } # false

### Count the number of member elements
items.count # 5
items.count { |i| i === 'thing' } # 2

### Get hash of occurance counts by item
items.tally # { "this"=>1, "thing"=>2, "the"=>1, "other"=>1 }

## Fetching: Return element(s) without modifying

### Return all elements
items.to_a # ["this", "thing", "the", "other", "thing"]
items.tally.to_a # [["this", 1], ["thing", 2], ["the", 1], ["other", 1]]
items.entries # ["this", "thing", "the", "other", "thing"]
items.tally.entries # [["this", 1], ["thing", 2], ["the", 1], ["other", 1]]

### Return first element
items.first # "this"

### Return the last element
items.last # "thing"

### Return some number of leading elements
items.take(2) # ["this", "thing"]

### Return some number of trailing elements
items.drop(2) # ["other", "thing"]

### Return leading elements as specified
items.take_while { |i| [4,5].include? i.length } # ["this", "thing"] 

### Return trailing elements as specified
items.drop_while { |i| [4,5].include? i.length } # ["the", "other", "thing"]

### Return elements of the smallest value using <=>
items.min # "other"
items.min(2) # ["other", "the"]
items.min { |a,b| a.size <=> b.size } # "the"
items.min(2) { |a,b| a.size <=> b.size } # ["the", "this"]

### Return elements of the largest value using <=>
items.max # "this"
items.max(2) # ["this", "thing"]
items.max { |a,b| a.size <=> b.size } # "thing"
items.max(2) { |a,b| a.size <=> b.size } # ["other", "thing"]

### Return smallest and largest elements
items.minmax # ["other", "this"]

### Return smallest element as specified
items.min_by { |i| i.length } # "the"

### Return largest element as specified
items.max_by { |i| i.length } # "thing"

### Return smallest and largest element as specified
items.minmax_by { |i| i.length } # ["the", "thing"]

### Return hash of elements grouped as specified
items.group_by { |i| i[0] } # { "t"=>["this", "thing", "the", "thing"], "o"=>["other"] }

### Return two arrays of elements partitioned as specified
items.partition { |i| i[0] === 't' } # [["this", "thing", "the", "thing"], ["other"]]

### Return enumerator of entries partitioned by given condition
items.slice_before { |i| i === 'thing' } # => #<Enumerator: ...>
items.slice_before { |i| i === 'thing' }.to_a # [["this"], ["thing", "the", "other"], ["thing"]]
items.slice_after { |i| i === 'thing' } # => #<Enumerator: ...>
items.slice_after { |i| i === 'thing' }.to_a # [["this", "thing"], ["the", "other", "thing"]]

### Return enumerator of entries grouped as specified
items.chunk { |i| i[0] } # => #<Enumerator: ...>
items.chunk { |i| i[0] }.to_a # [["t", ["this", "thing", "the"]], ["o", ["other"]], ["t", ["thing"]]]

### Return enumerator of entries sequentially grouped as specified
items.chunk_while { |a,b| a[0] == b[0] } # => #<Enumerator: ...>
items.chunk_while { |a,b| a[0] == b[0] }.to_a # [["this", "thing", "the"], ["other"], ["thing"]]

## Search and Filter

### Return first element as specified
items.find { |i| i == 'thing' } # "thing"
items.find { |i| i == 'grape' } # nil
items.detect { |i| i == 'thing' } # "thing"
items.detect { |i| i == 'grape' } # nil

### Return multiple elements as specified
items.find_all { |i| i == 'thing' } # ["thing","thing"]
items.find_all { |i| i == 'grape' } # []

### Return the index of the first element matching the condition
items.find_index { |i| i == 'thing' } # 1
items.find_index { |i| i == 'grape' } # nil

### Return array of elements not rejected by the condition
items.reject { |i| i[0] == 't' } # ["other"]

### Return array of elements which are not duplicated
items.uniq # ["this", "thing", "the", "other"]

### Return array of elements which match the specified object or pattern
items.grep(String) # ["this", "thing", "the", "other", "thing"]
items.grep(/thing/) # ["thing", "thing"]

### Return array of element which do not match the object or pattern
items.grep_v(String) # []
items.grep_v(/thing/) # ["this", "the", "other"]

## Sort

### Return elements sorted by <=> or as specified
items.sort # ["other", "the", "thing", "thing", "this"]
items.sort { |a,b| a[a.size-1] <=> b[b.size-1] } # ["the", "thing", "thing", "other", "this"]

## Return elements sorted as specified
items.sort_by { |i| i[i.size - 1] } # ["the", "thing", "thing", "other", "this"]

## Iterate

### Call a block with each successive element
items.each_entry { |i| print i } # prints "this" then "thing" et cetera

### Call a block with each successive element and its index
items.each_with_index { |i, idx| print "#{i} is at index #{idx}"} # prints "this is at index 0" et cetera

### Call a block with each successive element and an object
items.each_with_object([]) { |i, obj| obj << i[0..1] } # ["th", "th", "th", "ot", "th"]

### Make an enumerable of entries partitioned by size and call a block with each partition
items.each_slice(2) { |s| print s[0] } # prints "this" then prints "the" et cetera

### Make an enumerable of entries of specified size starting at each element and call a block on each partition
items.each_cons(2) # => #<Enumerable: ...>
items.each_cons(2).to_a # [["this", "thing"], ["thing", "the"], ["the", "other"], ["other", "thing"]]
items.each_cons(2) { |p| print p[0] } # prints "this" then prints "thing" et cetera

### Call a block with each successive element in reverse order
items.reverse_each { |i| print i } # prints "thing" then print "other" et cetera

## Other Methods

### Return a array of values by processing each entry as specified
items.map { |i| i.upcase } # ["THIS", "THING", "THE", "OTHER", "THING"]
items.collect { |i| i.upcase } # ["THIS", "THING", "THE", "OTHER", "THING"]

### Return an array of values which evaluate to truthy after processing each entry as specified
items.filter_map { |i| i[3] } # ["s", "n", "e", "n"]

### Return a single-dimension array as specified
items.flat_map { |i| [i, i.upcase] } # ["this", "THIS", "thing", "THING", "the", "THE", "other", "OTHER", "thing", "THING"]
items.tally.flat_map { |key, value| [key, value] } # ["this", 1, "thing", 2, "the", 1, "other", 1]

### Return the object formed by combining elements as specified
items.reduce('') { |obj, i| obj + i } # "thisthingtheotherthing"
items.inject('') { |obj, i| obj + i } # "thisthingtheotherthing"

### Return a summation object of elements using "+"
items.sum('') # "thisthingtheotherthing"
items.sum('') { |i| i[0] == 't' ? i : '' } # "thisthingthething"

### Return an array with each index being a combination of elements at the zipped arrays' indices
items.zip # [["this"], ["thing"], ["the"], ["other"], ["thing"]]
items.zip([]) # [["this", nil], ["thing", nil], ["the", nil], ["other", nil], ["thing", nil]]
items.zip(items.tally) # [["this", ["this", 1]], ["thing", ["thing", 2]], ["the", ["the", 1]], ["other", ["other", 1]], ["thing", nil]]

### Call a given block for each entry a specified number of times
items.cycle(2) { |i| print i[0] } # prints the first letter of each element, "t" then "t" then "t" then "o" then "t", two times
Enter fullscreen mode Exit fullscreen mode

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay