After the wackiness of the past couple of weeks — some travel to see family, followed by a busy week of tech events including DemoCamp 18, Damian Conway’s presentation, FAILCamp and RubyFringe — I’m happy to return to Enumerating Enumerable, the article series in which I attempt to do a better job at documenting Ruby’s Enumerable
module than Ruby-Doc.org does.
In this article, the eighth in the series, I’m going to cover a method introduced in Ruby 1.9: drop_while
.
I’m going through the Enumerable
‘s methods in alphabetical order. If you missed any of the earlier articles, I’ve listed them all below:
Enumerable#drop_while Quick Summary
In the simplest possible terms | Given a collection and a condition, return an array made of the collection’s items, starting the first item that doesn’t meet the condition. |
---|---|
Ruby version | 1.9 only |
Expects | A block containing the condition. |
Returns | An array made up of the remaining items, if there are any. |
RubyDoc.org’s entry | Enumerable#drop_while |
Enumerable#drop_while and Arrays
When used on an array, drop_while
returns a copy of the array created by going through the original array’s items in order, dropping elements until it encounters the an element that does not meet the condition. The resulting array is basically a copy of the original array, starting at the first element that doesn’t meet the condition in the block.
As in many cases, things become clearer with some examples:
# In Canada, and in fact in all but 2 countries in the world, # the weather report gives temperatures in Celsius! temperatures = [28, 25, 30, 22, 27] => [28, 25, 30, 22, 27] # The block returns true for the FIRST two elements, # and false for the third. # So drop_while returns an array like the original, # but starting at the third element. temperatures.drop_while {|temperature| temperature < 30} => [30, 22, 27] # The block returns false for the first element, # so drop_while returns an array like the original, # starting at the first element # (in other words, a copy of the original). temperatures.drop_while {|temperature| temperature < 28} => [28, 25, 30, 22, 27]
Enumerable#drop_while and Hashes
When used on a hash, drop_while
effectively:
- Creates an array based on the hash, with each element in the hash represented as a two-element array where the first element contains the key and the second element containing the corresponding value, then
- goes through each element in the array, dropping elements until it encounters the first element that doesn’t meet the condition in the block. The resulting array is an array of two-element arrays, starting at the first element that doesn’t meet the condition in the block.
Once again, examples will make this all clear:
# We're basically taking the array from the previous example # and dressing it up in a hash city_temperatures = {"New York" => 28, \ "Toronto" => 25, \ "Washington" => 30, \ "Montreal" => 22, \ "Boston" => 27} => {"New York"=>28, "Toronto"=>25, "Washington"=>30, "Montreal"=>22, "Boston"=>27} # The block returns true for the FIRST two elements, # and false for the third. # So drop_while returns an array based on the hash, # but starting at the third element # (and, of course, the key-value pairs turned into # two-element arrays). city_temperatures.drop_while {|city_temperature| city_temperature[1] < 30} => [["Washington", 30], ["Montreal", 22], ["Boston", 27]] # This is a more readable version of the line above city_temperatures.drop_while {|city, temperature| temperature < 30} => [["Washington", 30], ["Montreal", 22], ["Boston", 27]] # The block returns false for the first element, # so drop_while returns an array based on the hash, # starting at the first element # (in other words, an array based on the original hash, # with key-value pairs turned into two-element arrays). city_temperatures.drop_while {|city,temperature| temperature < 28} => [["New York", 28], ["Toronto", 25], ["Washington", 30], ["Montreal", 22], ["Boston", 27]]
Enumerable#drop_while’s Evil Twin, Enumerable#take_while
I’ll cover take_while
in detail in a later installment, but for now, an example should suffice:
city_temperatures.drop_while {|city_temperature| city_temperature[1] < 30} => [["Washington", 30], ["Montreal", 22], ["Boston", 27]] city_temperatures.take_while {|city_temperature| city_temperature[1] < 30} => [["New York", 28], ["Toronto", 25]]
5 replies on “Enumerating Enumerable: Enumerable#drop_while”
Aren’t these virtually the same as reject and select?
@Gianni Chiappetta: They’re similar, but not the same.
drop_while
andtake_while
go through the collection’s items in order and stop as soon as the condition in the block is no longer met, whereasreject
andselect
don’t operate under that constraint.Here’s an example showing the difference:
In the
drop_while
example above, the first element,28
, causes the condition in the block to returnfalse
.drop_while
stops checking the remaining elements and returns the result array. So in the case of thetemperatures
array above,drop_while
‘s result is equal to the original array.drop_while
will return the same results asreject
if the array is sorted in such a way that all the elements that meet the condition in the block are moved to the beginning of the collection. In the case of thetemperatures
array, that’s easy:The practical upshot of all this is that you can think of
drop_while
(and its evil twintake_while
) as “lazy evaluation” versions ofreject
andselect
where the order of the collection matters.As for practical uses for
drop_while
? I’m sure there are some, but I’m feeling a little lazy today and will use the standard cop-out: “I’ll leave that as an exercise for the reader.”Ahh I see, thanks for clearing that up Joey!
[…] have no excuse for blowing this. I’ve actually written a whole series of articles on the power of Ruby’s Enumerable module, including the select method (and what I think was a pretty […]
[…] have no excuse for blowing this. I’ve actually written a whole series of articles on the power of Ruby’s Enumerable module, including the select method (and what I think was a pretty […]