0% found this document useful (0 votes)
37 views

Ruby - Understanding Enumerable

The document discusses Ruby's Enumerable module and how it provides common array methods like each, map, select, etc to classes like Array, Range and Hash. It demonstrates how these methods work on different data types and how a module can be included to share behavior between classes.

Uploaded by

g_teodorescu
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
37 views

Ruby - Understanding Enumerable

The document discusses Ruby's Enumerable module and how it provides common array methods like each, map, select, etc to classes like Array, Range and Hash. It demonstrates how these methods work on different data types and how a module can be included to share behavior between classes.

Uploaded by

g_teodorescu
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 9

Understanding Enumerable

by Pete Nicholls on 17 Oct 2013 at Christchurch Ruby The first few sections are aimed at newcomers to Ruby, so feel free to skip it if you already know it. Enumerable is a fascinating mixin. ts use ma!es for unusual" characteristic" an# ex$ressi%e Ruby co#e. n this tal!" &e'll ta!e a loo! at Ruby's Array class" #iscuss &hy Rubyists #on't use for" an# learn ho& to count the uncountable.

Forming arrays
(hen first starting &riting Ruby" remember being im$resse# &ith the brea#th an# ex$ressi%eness of the stan#ar# library. Perha$s none stoo# out to me more than the Array class. )et's loo! at a fe& exam$les. *ou can try any of these exam$les using the interacti%e console that shi$s &ith Ruby" irb. +ust ty$e irb in a terminal an# hit return to start an interacti%e Ruby session. )et's start by creating an array,
parents = ["Ned", "Catelyn"] # => ["Ned", "Catelyn"]

Nothing out of the or#inary here" but there's a sim$ler &ay to &rite arrays of &hites$acese$arate# %alues,
children = %w( Robb ansa Arya !ran Ric"on # # => ["Robb", " ansa", "Arya", "!ran", "Ric"on"]

No&" let's combine the t&o arrays together,


star"s = parents $ children # => ["Ned", "Catelyn", "Robb", " ansa", "Arya", "!ran", "Ric"on"]

.eems natural" right/ .ubtraction &or!s too,


star"s % children # => ["Ned", "Catelyn"]

0ccessing items,
star"s&first star"s&at('# star"s[%(] # star"s['&&)] # => "Ned" # => " ansa" => "Ric"on" # => [" ansa", "Arya", "!ran"]

n the last exam$le" '&&) is a Ran*e. (e'll come bac! to those later.

Array iteration
Ruby has a for loo$,
for na+e in star"s p,ts na+e end

*ou &on't often see it use#" though. nstea#" most Rubyists &ill use each,
star"s&each do -na+ep,ts na+e end

1here's an im$ortant #istinction" an# &e'll come bac! to it later. 2or the moment" 3ust ta!e a loo! at this exam$le. 4et&een the do an# end &e ha%e a bloc!. *ou can thin! of a bloc! as an anonymous function or a closure" if you're familiar &ith those conce$ts. Other&ise" 3ust thin! of it as a 5bloc!6 of co#e. 1he bloc! gets execute# once $er item in the array. 0nother &ay to &rite a bloc! is &ith curly braces. 1he follo&ing is i#entical to the last exam$le,
star"s&each . -na+e- p,ts na+e /

(hat if &e &ante# the in#ex" too/


star"s&each0with0inde1 . -na+e, i- p,ts "#.i/& #.na+e/" /

(hich &oul# $rint,


(& Ned 2& Catelyn '& Robb &&&

Filtering and sorting arrays


7any of the metho#s on arrays use bloc!s. )et's try filtering an array,
star"s&select . -na+e- na+e&end0with3(4a4# / # => [" ansa", "Arya"]

(hen using select" the return value of the bloc! &ill be e%aluate# to #etermine &hich elements are returne# in the ne& array. n Ruby" all metho#s an# bloc!s ha%e a return %alue" in this case the last line of the bloc!.

.imilar to select" &e ha%e re5ect,


star"s&re5ect . -na+e- na+e&incl,de3(4a4# / # => ["Ned", "Robb", "Ric"on"] sort

is a%ailable,

star"s&sort # => ["Arya", "!ran", "Catelyn", "Ned", "Ric"on", "Robb", " ansa"]

4ecause most metho#s on array return another array" you can chain metho#s together,
star"s&sort&re6erse # => [" ansa", "Robb", "Ric"on", "Ned", "Catelyn", "!ran", "Arya"]

8ere" &e're using a bloc! sorting by the length of their name,


star"s&sort0by . -na+e- na+e&len*th / # => ["Ned", "Robb", "Arya", "!ran", " ansa", "Ric"on", "Catelyn"]

f you &ant to call a single metho# on each item" there's a shorthan# syntax for that,
star"s&sort0by(78len*th#

&on't #iscuss ho& this &or!s" but it's $retty neat if you &ant to fin# out for yourself.

Transforming arrays
(hat if &e &ante# to transform all the names/
star"s&+ap . -star"- star"&,pcase / # => ["N9:", "CA;9<=N", "R>!!", " AN A", "AR=A", "!RAN", "R?C@>N"]

)et's a## the last name to each member of the .tar! house. 1his time" &e're going to use +ap's brother" +apA,
star"s&+apA . -first0na+e- "#.first0na+e/ # => ["Ned tar"", "Catelyn tar"", "Robb tar"", "!ran tar"", "Ric"on tar""] tar"" / tar"", " ansa tar"", "Arya

1he #ifference bet&een +ap an# +apA is that +ap &ill return a new array" &hile +apA &ill mo#ify the existing array. n the same &ay" select an# re5ect ha%e selectA an# re5ectA counter$arts that mo#ify the original array rather than retuen a ne& one. Ruby Tip: 1he exclamation mar! 9also !no&n as the bang:" is a $erfectly %ali# character to use as $art of a metho# name. Rubyists ten# to use exclamation mar!s at the en# of their metho#s to let other #e%elo$ers !no& that the metho# is #angerous. t might be ma!ing $ermanent changes to your ob3ect" #atabase" or #oing something unex$ecte#.

earching for answers


No& that &e ha%e all our .tar!s $ro$erly name#" let's a## one more,
star"s BB "Con now" # => ["Ned tar"", "Catelyn tar"", "Robb tar"", " ansa tar"", "!ran tar"", "Ric"on tar"", "Con now"] tar"", "Arya

8o& &oul# &e !no& if this array containe# someone &hose last name &as .no&/ (e coul# use select" but it &oul# ha%e to iterate through e%ery item in the array" e%en if it ha# alrea#y foun# a .no&. (oul#n't it be better if &e ha# a metho# that returne# tr,e the moment it foun# one/
star"s&any3 . -na+e- na+e&ends0with3(4 now4# / # => tr,e

1he ;uestion mar! in the any3 metho# is similar to the exclamation mar! before < it's sim$ly a Ruby con%ention" this time to in#icate a metho# that returns a true 9or truthy: %alue.
star"s&all3 . -na+e- na+e&ends0with3(4 tar"4# / # => false star"s&delete(4Cohn now4# star"s&all3 . -na+e- na+e&ends0with3(4 tar"4# / # => tr,e

Range iteration
No& you'%e seen a fe& tric!s from the Array class" let's ta!e a loo! at another common class" Ran*e,
(D&&)#&each . -n- p,ts n /

Notice ho& &e're using each again. 8ere's a metho# that allo&s us to iterate o%er the range in slices,
((&&(DD#&each0slice()# . -set- p,ts set&inspect /

(hich &oul# $ro#uce,


[(, 2, ', E, )] [F, G, H, I, (D] &&&snip&&& [IF, IG, IH, II, (DD]

!ounting to "nfinity
n most languages" #i%i#ing by =ero raises an error,
>>> (&DJD ;racebac" (+ost recent call last#8 Kile "Bstrin*>", line (, in B+od,le>

>

Lero:i6ision9rror8 float di6ision by Mero

Not so in Ruby,
?nfinity = (&DJD # => ?nfinity

nterestingly" you can create a range that uses nfinity,


all0positi6e0n,+bers = D&&?nfinity all0positi6e0n,+bers&incl,de3('# # => tr,e all0positi6e0n,+bers&incl,de3(E('E'(2E# # => tr,e ,s0debt = (G0DDD0DDD0DDD0DDD all0positi6e0n,+bers&incl,de3(,s0debt# # => tr,e

*ou can e%en create a range bet&een negati%e an# $ositi%e nfinity,
all0n,+bers = %?nfinity&&?nfinity all0n,+bers&incl,de3(%')F2'# # => tr,e

*ou coul#" if you &ante# to" use each to iterate o%er e%ery $osti%e number.
all0positi6e0n,+bers&each . -n- p,ts n /

t may ta!e some time. 4etter" $erha$s" to ta!e 3ust a fe&,


all0positi6e0n,+bers&ta"e()# # => [D, (, 2, ', E]

Or $erha$s in slices,
all0positi6e0n,+bers&each0slice()#&ta"e(2# # => [[D, (, 2, ', E], [), F, G, H, I]]

Notice ho& &e #i#n't $ass a bloc! to each0slice this time/ &on#er &hat ha$$ens if &e 3ust call each by itself/
en,+erator = all0positi6e0n,+bers&each # => #B9n,+erator8 D&&?nfinity8each> en,+erator&ne1t # => D en,+erator&ne1t # => ( en,+erator&ne1t # => 2

nteresting.

#ashes
8ashes allo& table-li!e ma$$ings bet&een names an# %alues,
si*ils = . 4 tar"4 => 4:irewolf4, 4<annister4 => 4<ion4, 4Nrey5oy4 => 4@ra"en4

8ashes" too" ha%e an each metho#,


si*ils&each do -ho,se, ani+alp,ts ";he si*il of Oo,se #.ho,se/ is a #.ani+al/&" end

)et's ha%e a loo! at the metho#s on a 8ash,


Oash&instance0+ethods # => [&&&, 8each, 8+ap, 8select, 8re5ect, 8all3, 8any3, &&&]

8mm" these are the same metho#s that a$$ear on the Array an# Ran*e classes.

"ntroducing Enumerable
Array" Ran*e"

an# Oash share a number of i#entical 9an# useful: metho#s. 8o& is this

ha$$ening/
Oash&incl,ded0+od,les # => [9n,+erable, P] Array&incl,ded0+od,les # => [9n,+erable, P] Ran*e&incl,ded0+od,les # => [9n,+erable, P]

Each of these classes inclu#e the 9n,+erable mo#ule. (hat #oes that #o/
9n,+erable&instance0+ethods # => [8to0a, 8entries, 8sort, 8sort0by, 8*rep, 8co,nt, 8find, 8detect, 8find0inde1, 8find0all, 8select, 8re5ect, 8collect, 8+ap, 8flat0+ap, 8collect0concat, 8in5ect, 8red,ce, 8partition, 8*ro,p0by, 8first, 8all3, 8any3, 8one3, 8none3, 8+in, 8+a1, 8+in+a1, 8+in0by, 8+a10by, 8+in+a10by, 8+e+ber3, 8incl,de3, 8each0with0inde1, 8re6erse0each, 8each0entry, 8each0slice, 8each0cons, 8each0with0ob5ect, 8Mip, 8ta"e, 8ta"e0while, 8drop, 8drop0while, 8cycle, 8ch,n", 8slice0before, 8laMy]

0ha@ 1he metho#s &e'%e been using ha%e been #efine# insi#e the 9n,+erable mo#ule.

$hat%s a module&
0 mo#ule is a collection of metho#s. 7o#ules are sometimes calle# 5mixins6" because you can mix in the metho#s #efine# in a mo#ule into a class. Ao you ba!e/ 'm terrible at it. can ne%er remember to !ee$ an eye on the time. )et's &rite some Ruby that !no&s ho& to ba!e,
+od,le !a"in* def ba"eA "!a"in* for #.coo"in*0ti+e/ at #.te+perat,re/" end end

0n# let's a## our ne&foun# ba!ing $ro&ess to a ca!e,

class Ca"e incl,de !a"in* def coo"in*0ti+e "E) +ins" end def te+perat,re "(HDQC" end end

0n# no& our ca!e !no&s ho& to ba!e itself,


ca"e = Ca"e&new ca"e&ba"eA # => "!a"in* for E) +ins at (HDQC"

'rowsing books
)et's say &e ha# a !oo" an# a !oo"shop class,
class !oo" B end tr,ct&new(8title, 8price#

class !oo"shop def initialiMe(boo"s# Rboo"s = boo"s end def n,+ber0of0boo"s Rboo"s&len*th end end

1he tr,ct is a little tric! &e're using to s!etch out the classes.
!oo"

an# !oo"shop can be use# li!e this,

boo"s = [ !oo"&new(4;he <ittle !oo" of Cal+4, 2&2D#, !oo"&new(4Co+plete Sor"s of :ic"ens4, 'DD#, !oo"&new(4;he 9lephant and the !alloon4, )# ] blac"0boo"s = !oo"shop&new(boo"s# blac"0boo"s&n,+ber0of0boo"s # => '

8o& coul# &e bro&se through each of the boo!s in the boo!store/

(efining each
)et's ma!e our o&n each" &hich &ill han# us each of the boo!s,
class !oo"shop # &&&snip&&&

def each Rboo"s&each . -boo"- yield boo" / end end

8ere's ho& you coul# use the each metho# &e'%e im$lemente#,
boo"shop&each do -boo"p,ts boo"&title end

Our each 3ust calls each on the un#erlying Rboo"s array. *our each coul# be much more interesting < e%ery iteration of each coul# execute a #atabase ;uery" or ;uery a &eb ser%ice" or ta!e a rea#ing from a &eather station" for exam$le. t's entirely u$ to you.

)i*ing in the magic


1he cle%er bit comes &hen &e inclu#e the 9n,+erable mo#ule.
class !oo"shop incl,de 9n,+erable # &&&snip&&& end

No&" &e can use all the &on#erful metho#s &e coul# &ith Array" Ran*e" an# Oash,
boo"shop&filter . -boo"- boo"&price B= )&DD / boo"shop&any3 . -boo"- boo"&title&start0with3(4Co+plete4# / &&& 9n,+erable

gi%es you all these metho#s for free. *ou 3ust nee# to #efine &hat each means

to you.

'uilding on the abstraction


(e can also easily im$lement metho#s using 9n,+erable-$ro%i#e# metho#s,
class !oo"shop # &&&snip&&& def prices +ap(78price# end def titles +ap(78title# end def ,nder0ten0dollars filter . -boo"- boo"&price B (D / end def total06al,e0of0stoc"

prices&in5ect(8$# end end

)et's ta!e a loo!,


blac"0boo"s&prices # => [2&2D, 'DD, )] blac"0boo"s&,nder0ten0dollars # a list of boo"s blac"0boo"s&total06al,e0of0stoc" # => 'DG&2

Neat@

(ucking under the hood


Array" Ran*e" an# Oash all im$lement their o&n each metho#" an# then sim$ly inclu#e 9n,+erable mo#ule to get all of the con%ienient metho#s. 8o& #oes that &or!/

the

(ell" here's ho& +ap coul# ha%e been im$lemente# insi#e 9n,+erable,
+od,le 9n,+erable def +ap new0collection = [] self&each do -ite++odified0ite+ = yield ite+ new0collection BB +odified0ite+ end new0collection end end

n other &or#s" all the metho#s you'%e seen so far 9select" each0with0inde1" all3" +ap" etc.: ha%e been &ritten $urely in terms of each. 1his is a beautiful exam$le of $olymor$hism in the &il#. 4y abstracting a&ay the un#erlying class or #ata structure" 9n,+erable sol%es a number of common $roblems concerning collections in one fell s&oo$. t can han#le e%erything from hashes to boo!sho$s.
9n,+erable,

sim$le" flexible" an# beautiful. +ust li!e Ruby.

Further reading

Enumerable #ocumentation 0 Dui#e to Ruby Collections

You might also like