You are on page 1of 41

_w:11807:1623034923

ITERATORS & BLOCKS


RECAP
ARRAY
musicians = ['David Gilmour', 'Roger Waters', 'Richard Wright'

musicians.size # => 4
musicians[1] # => "Roger Waters"
musicians << 'Syd Barrett' # => [..., 'Syd Barrett']
RANGE
Collection of successive elements
0..10 # including upper bound
# => 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

0...10 # excluding upper bound


# => 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

(0..10).to_a # conversion to array


# => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

rubydoc for Range


ARRAY ITERATION
LOOPING WITH FOR ON INDICES
Let's loop through the indices
for index in 0...(musicians.size)
musician = musicians[index]
puts "#{index + 1} - #{musician}"
end

# => 1 - David Gilmour


# 2 - Roger Waters
# 3 - Richard Wright
# 4 - Nick Mason
LOOPING WITH FOR ON ELEMENTS
Or directly on the elements
for musician in musicians
puts "Listen to #{musician}"
end

# => Listen to David Gilmour


# Listen to Roger Waters
# Listen to Richard Wright
# Listen to Nick Mason
WELL, THAT'S NOT IDIOMATIC.
ITERATORS
#EACH
Live-code: Let's greet musicians one by one.
musicians.each do |musician|
puts "Hello #{musician}!"
end

# => Hello David Gilmour!


# Hello Roger Waters!
# Hello Richard Wright!
# Hello Nick Mason!
#EACH_WITH_INDEX
Live-code: Let's display an ordered list of musicians.
musicians.each_with_index do |musician, index|
puts "#{index + 1} - #{musician}"
end

# => 1 - David Gilmour


# 2 - Roger Waters
# 3 - Richard Wright
# 4 - Nick Mason
THERE'S MORE
#MAP
"Transform" one array to another one by applying some code
on each element.
#MAP - UPCASED NAMES
Live-code: Let's build an array of upcased musician names.
musicians = ['David Gilmour', 'Roger Waters', 'Richard Wright'

upcased_musicians = musicians.map do |musician|


musician.upcase
end

p upcased_musicians
# => ['DAVID GILMOUR', 'ROGER WATERS', 'RICHARD WRIGHT', 'NICK MASON']
#MAP - FIRST NAMES
Live-code: Let's build an array of musician first names.
musicians = ['David Gilmour', 'Roger Waters', 'Richard Wright'

musician_first_names = musicians.map do |musician|


musician.split.first
end

p musician_first_names
# => ['David', 'Roger', 'Richard', 'Nick']
#COUNT
Count element of an array for which some code is true
Live-code: count musicians starting with "R"
musicians = ['David Gilmour', 'Roger Waters', 'Richard Wright'

r_musicians_count = musicians.count do |musician|


musician.start_with?("R")
end

p r_musicians_count
# => 2
#SELECT
Filter from an array elements for which some code is true
Live-code: extract musicians starting with "R"
musicians = ['David Gilmour', 'Roger Waters', 'Richard Wright'

r_musicians = musicians.select do |musician|


musician.start_with?("R")
end

p r_musicians
# => ['Roger Waters', 'Richard Wright']
AND MANY MORE
http://www.ruby-doc.org/core/Array.html
http://www.ruby-doc.org/core/Enumerable.html

(Today's first challenge is to pick the right methods from this


documentation)
TO SUMMARIZE...
#EACH,, #MAP
#EACH #MAP,, #COUNT ...
#COUNT...
Are called iterators.
Enumerable is a module included in the Array class.
An iterator is just a method of Enumerable.
UNDERSTAND WHAT THEY RETURN
# .each -> the object it was called on (!)
# .map -> a new Array with transformed elements
# .count -> an Integer
# .select -> a new Array with elements that met a condition
UNDERSTAND HOW THEY WORK
The block of code has a different role in each case.
musicians.each { |musician| any_code_with(musician) }
musicians.map { |musician| transform(musician) }
musicians.select { |musician| condition_on(musician) }
WHAT THE HELL WAS THIS?
do |musician|
musician.upcase
end

This is a piece of code called a block


BLOCKS
Blocks are pieces of code

You can think of blocks as anonymous methods.


BLOCK SYNTAX
1-line syntax
{ |num| num * 2 }

multi-line syntax
do |num|
num * 2
end
BLOCK RETURN
A multi-line block works as a method, it returns the last
statement executed.
musicians = ['David Gilmour', 'Roger Waters', 'Richard Wright'

upcased_first_names = musicians.map do |musician|


first_name = musician.split.first
upcased_first_name = first_name.upcase
puts "[DEBUG] #{musician}'s first name is #{upcased_first_name}

upcased_first_name
end
METHODS USING A BLOCK
Multi-line syntax
method(arg_1, ...) do |block_arg_1, ...| # A block can pass on multipl
# Some code
end

Or with the 1-line syntax


method(arg_1, ...) { |block_arg_1, ...| some_code }

IMPORTANT
The block is just an argument of the method
EXAMPLE #EACH
[1, 2, 3].each do |number|
# Do what ever you want with each number
end

[1, 2, 3].each { |number| some_code }

Remember, those two syntaxes are the same


The block is part of the method call
DEFINE METHODS USING BLOCKS
DISCLAIMER
Advanced concept, normal if you struggle!
You'll probably never have to define such methods in your
ruby/Rails career.
But you will use lots of them (like each, map, etc..)
YIELD CALLS THE BLOCK
yield is a Ruby keyword executing the block.
Live-code: let's code a timer method
def timer
start_time = Time.now
yield
puts "Elapsed time: #{Time.now - start_time}s"
end

timer() do
puts "I'm doing something slow..."
sleep(4)
puts "I'm done :)"
end
# => I'm doing somethings slow...
# => I'm done :)
# => Elapsed time: 4s
FLOW OF A METHOD CALLED WITH A BLOCK (1)
FLOW OF A METHOD CALLED WITH A BLOCK (2)
FLOW OF A METHOD CALLED WITH A BLOCK (3)
FLOW OF A METHOD CALLED WITH A BLOCK (4)
FLOW OF A METHOD CALLED WITH A BLOCK (5)
YIELD CAN BE CALLED WITH PARAMETERS
Live-code: let's code a custom greeting method.
def greet(first_name, last_name)
full_name = "#{first_name.capitalize} #{last_name.upcase}"
return "Hello, #{full_name}"
end

puts greet('john', 'lennon') # "Hello, John LENNON"

We want to customize this greeting message with a block.


USING A BLOCK
def beautify_name(first_name, last_name)
full_name = "#{first_name.capitalize} #{last_name.upcase}"
yield(full_name)
end

message = beautify_name("john", "lennon") do |name|


"Greetings #{name}, you look quite fine today!"
end
puts message # => "Greetings John LENNON, you look quite fine today!"

message = beautify_name("john", "lennon") do |name|


"Bonjour #{name}, comment allez-vous ?"
end
puts message # => "Bonjour John LENNON, comment allez-vous ?"

message = beautify_name("ringo", "starr") do |name|


"Hey #{name}! Let's play on your #{name} drum kit!"
end
puts message # => "Hey Ringo STARR! Let's play on your Ringo STARR dru
YOUR TURN!

You might also like