This is part of the Back to Basics series.
See the introductory article for an explanation of why this series is important.

Last time, on “Enumerable: Scratching that Each” (way back in 2019), we learned about the 65 different versions of each and when and how to use …er… each of them.

This time we are going to work on various ways of fetching simple sequences of elements from an enumerable object.

Here is a quick summary:



Let’s start with the simplest task: return all the items in a collection.

to_a or its alias entries does just that:

class PocketContentGuesses
  include Enumerable
  
  def each
    yield "handses"
    yield "knife"
    yield "string", "nothing"
  end
end
p PocketContentGuesses.new.to_a
["handses", "knife", ["string", "nothing"]]

Doesn’t come up too often unless you need to serialize a collection as an array somewhere.



Next, let’s just get the first item in the collection:

%w[a b c d].first # => "a"

Note that if the collection is empty, you get nil:

[].first #=> nil


Let’s step it up a notch. What if we want to get the first n elements from a collection (where n is a non-negative number)?

take(n), aka first(n) returns this new array:

%w[a b c d].take(2) #=> %w[a b]

If you “take” 0 elements, you get an empty array:

%w[a b c d].first(0) #=> []

If you “take” a number that is more than the number of elements in the collection, you just get the whole collection:

%w[a b c d].take(10) #=> %w[a b c d]


Cool. What if we want to skip n elements from a collection, then return the remainder?

drop(n) returns this new array:

%w[a b c d].drop(2) #=> %w[c d]

If you “drop” 0 elements, you get the full collection back as a new array (similar to to_a)

%w[a b c d].drop(0) #=> %w[a b c d]

If you “drop” too many elements, you get an empty array back.

%w[a b c d].drop(4) #=> []


Both of these “take” and “drop” concepts also have a block form.

take_while { |item| ... } “takes” elements while the given block returns a truthy value:

[1, 1, 2, 3, 5, 8].take_while { |item| item.odd? } #=> [1, 1]

If all of the items in the list return true from the block, then you get the full collection back as an array (just like to_a or take(10)):

[1, 1, 2, 3, 5, 8].take_while(&:positive?) #=> [1, 1, 2, 3, 5, 8]

If the first item in the list returns false from the block, then you get an empty array:

[1, 1, 2, 3, 5, 8].take_while(&:even?) #=> []


drop_while { |item| ... } “drops” elements while the given block returns a truthy value, and returns the remainder as an array:

[1, 1, 2, 3, 5, 8].drop_while { |item| item.odd? } #=> [2, 3, 5, 8]

If all of the items in the list return true from the block, then you get an empty array back:

[1, 1, 2, 3, 5, 8].drop_while(&:positive?) #=> []

If the first item in the list returns false from the block, then you get the full collection back as an array (just like to_a or drop(0)):

[1, 1, 2, 3, 5, 8].drop_while(&:even?) #=> [1, 1, 2, 3, 5, 8]


To read the rest of the series: click here