- Review Ruby arrays and hashes
- Use Ruby loops to iterate over code blocks.
- Define what a Ruby enumerable method is.
- Use enumerables to traverse, sort and modify collections.
- Identify useful Ruby enumerables, including
.each
,.map
and.select
.
One of the most common things we do as developers is to loop through data structures. We understand and learned how to do these things in Javascript. Now we're going to learn how to do them in ruby. We'll start with the basics but then..
We will be going over enumerables in Ruby, one of the most powerful modules that comes included in the language out of the box.
We will get into how to use enumerables later on this lesson, but first just know that enumerables essentially are a more readable, expressive way to work with collections of data in Ruby.
Whenever we talk about data in Ruby, its important to review how Ruby handles groups of data.
Q: What are the different types of collections in Ruby?
fruits = ["apple", "banana", "cherry"]
fruits.length # 3
fruits.push("date")
fruits.length # 4
fruits[0] # apple
fruits[3] # date
fruits[3] = "mango"
fruits[3] # mango
fruits.join(" ") # "apple banana cherry mango"
fruits.join(", ") # "apple, banana, cherry, mango"
fruits.join(" and ") # "apple and banana and cherry and mango "
A: using
<<
, or the shovel operator: e.g.fruits << "peach"
Hashes are like Javascript Object Literals, but they are a bit more limited:
instructor = {
name: "Bob",
age: 30,
favorite_foods: ["Tater Tots", "Cheese Steaks", "Kale Salad"]
}
# Access values from a hash
instructor[:name] # "Bob"
instructor[:age] # 30
instructor[:favorite_foods] # ["Tater Tots", "Cheese Steaks", "Kale Salad"]
# Set values to an existing key
instructor[:name] = "Robert"
instructor[:name] # "Robert"
# Add new key-value pairs
instructor[:favorite_color] = "red"
instructor[:favorite_color] # "red"
- What's another "rubyist" way to add items to an array?
- What is one main difference between Ruby's
hashes
and Javascript'sobject literals
? - What are some useful methods we can call on collections?
- Where would I go look if I wanted to find more methods?
Another similarity Ruby shares with Javascript is base support for various types of loops.
A:
while
,do-while
,for
,for-in
,forEach
Let's start by reviewing JS for
loops.
Say we had our fruits
example from earlier and we wanted to print each individual fruit in the console
var fruits = ["apple", "banana", "cherry"];
for (var i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
The closest equivalent to Javascript's for
loop is Ruby's for-in
loop
fruits = ["apple", "banana", "cherry"]
for fruit in fruits do
puts fruit
end
Ruby also has a plethora of other types of loops including:
loop
- loop runs uninterrupted until stopped
while
- runs the loop while the condition is true
until
- runs the loop while the condition is false
.times
(called on a number)- runs the loop a specific of times
10.times.do |i|
puts i
end
What does this code do? (ST-WG)
break
lets us end -- or "break" out of -- a loop.
10.times do |i|
if i == 5
break
end
puts i
end
next
lets us skip to the next iteration of a loop.
10.times do |i|
if i == 5
next
end
puts i
end
As the new manager of GA's Club Code, you been tasked with creating an automated bouncing system.
The club's rules state:
- Only people 18 and over are allowed in the door
- No more than 8 people should be inside the club at any time
Given a line of people:
people = [
{ name: "Jack", age: 16 },
{ name: "Sam", age: 21 },
{ name: "Jill", age: 23 },
{ name: "Paul", age: 20 },
{ name: "Mike", age: 16 },
{ name: "Stan", age: 70 },
{ name: "Chris", age: 17 },
{ name: "Julie", age: 45 },
{ name: "Suzy", age: 65 },
{ name: "Eli", age: 28 },
{ name: "Katie", age: 50 },
{ name: "Ben", age: 33 }
]
and using what you know about loops and collections in Ruby, write a program that:
- Creates a new array of people inside the club
- Allows the appropriate people into the club
- Stops once 8 people have been admitted
Hints:
- How could you use
next
and/orbreak
to alter the behavior of a loop?
Bonus
- Determine whether or not a person is to be served
- Anyone over 18, but under 21 can come in, but they are not to be served adult beverages
- Create a new key-value pair for each
person
withserved
as aboolean
Double Bonus
- Write a function that takes 3 arguments: a list of people, an age limit, and capacity limit.
- It should return a hash that looks like this:
{ accepted: [ {name: "Jack", age: 22}, {name: "Jill", age: 31}, ...], rejected: [ {name: "Billy", age: 18}, {name: "Nancy", age: 31}, ...] }
The Enumerable module provides a set of methods to traverse, search, sort and manipulate collections.
So how are enumerables different than loops you might ask? In general, loops just execute a certain block of code for a given amount of time, while enumerables are used in relation to data collections to more easily control and transform values in data sets.
Since we already have a base understanding of loops and arrays and hashes, there's nothing new conceptually here. But you'll learn to do more with prettier, fewer lines of code.
The king (or queen) of enumerables, and the one you will most likely be using the most.
- Iterates through and performs an action(s) on a collection.
- Note: Does not permanently modify the collection.
If we were to emulate .each
using plain ol' Ruby, it would look something like this...
# A loop that prints out the doubled value of each item in an array
numbers = [ 1, 2, 3, 4, 5 ]
i = 0
while(i <= numbers.length) do
puts numbers[i] * 2
i = i + 1
end
But using .each
looks like this, with the code block format...
numbers = [ 1, 2, 3, 4, 5 ]
numbers.each do |number|
puts number * 2
end
# Alternate syntax
numbers = [ 1, 2, 3, 4, 5 ]
numbers.each { |number| puts number * 2 }
Visualize: EACH: using this code visualizer let's look at how each
operates under the hood
The
each
method yields a reference to each element in the collection, rather than a reference to the element's numerical index in the array.
WHITEBOARD: You'll notice we wrote out the .each
example in two ways: multi-line and single-line.
Multi-line
.each
- method namedo
- keyword that begins block of code|number|
- iteration variable; represents an individual value in the array- Common syntax is to name the variable the singular version of the collection. In this case, use
number
fornumbers
. - Some enumerables may have more than one of these.
- Common syntax is to name the variable the singular version of the collection. In this case, use
end
- closes code block
Single-line
.each
- method name- { } - replaces
do
andend
; contains the iteration variable and code block |number|
- iteration variable
Use each
to do the following...
-
Say hello to everybody in the below array of names (sample output:
Hello Donald!
).names = [ "Donald", "Daisy", "Huey", "Duey", "Luey" ]
-
Print out the squared values of every number in this numbers array.
numbers = [ 1, 3, 9, 11, 100 ]
-
Print out the Celsius values for an array containing Fahrenheit values.
fahrenheit_temps = [ -128.6, 0, 32, 140, 212 ]
-
Insert all the values in the
artists
array into theninja_turtles
array.artists = [ "Leonardo", "Donatello", "Raphael", "Michelangelo" ] ninja_turtles = []
-
Bonus: Print out every possible combination of the below ice cream flavors and toppings.
flavors = [ "vanilla", "chocolate", "strawberry", "butter pecan", "cookies and cream", "rainbow" ] toppings = [ "gummi bears", "hot fudge", "butterscotch", "rainbow sprinkles", "chocolate sprinkles" ]
Let's get a quick Fist-of-Five on how we feel about each
and enumerables so far?
- There are many enumerable methods. All of them look and feel similar to
each
.
Map is similar to each
. It iterates through each element in the collection, but map
generates a new collection with values based on the code block. Say we want to double our numbers
array and store it in a new array...
numbers = [ 1, 2, 3, 4, 5 ]
doubles = numbers.map do |number|
number * 2
end
doubles
# => [ 2, 4, 6, 8, 10 ]
# Alternate syntax
numbers = [ 1, 2, 3, 4, 5 ]
doubles = numbers.map { |number| number * 2 }
doubles
NOTE: We did not have to type out any variable assignment in the code block!
VISUALIZE: MAP: using this code visualizer let's look at how map
operates under the hood
Use map
to do the following...
- Create an array that appends "Duck" to everybody in this array of first names
first_names = [ "Donald", "Daisy", "Daffy" ]
#=> ["Donald Duck", "Daisy Duck"]
- Create an array containing the squared values of every number in this array.
numbers = [ 1, 3, 9, 11, 100 ]
# => [1, 9, 81, 121, 10000]
- Create an array with the Celsius values for these Fahrenheit values.
fahrenheit_temps = [ -128.6, 0, 32, 140, 212 ]
#=> [-89.2, -17.8, 0, 60, 100]
Instructions: Each group will spend 10 minutes using Ruby documentation to look up an assigned enumerable. Prepare the following for your demo:
- your own definition of what it does
- whiteboard an example.
- at a high level, try to find/think of a use case of this enumerable in the wild, doesn't have to be the actual code just conceptually similar
- You can test your example in IRB/Pry.
- Documentation
Groups
- Group 1: Each With Index
- Group 2: Reject
- Group 3: Find
- Group 4: Select
- Group 5: Sort By
- Group 6: Inject/Reduce
Bonus: If you find yourself with extra time, you can:
- Pick out another enumerable that wasn't assigned to a group.
- ...and/or think of another example for your assigned enumerable.
Combine your knowledge of Ruby basics and enumerables to make our old nemesis a piece of cake...
- What is the difference between
loops
andenumerables
in Ruby? - What are some examples of loops in Ruby that are not in JS?
- Differentiate between Ruby's
each
andmap
methods - What is an
iteration
variable? - List 5 useful Ruby enumerable methods