Intermediate Ruby, Array Methods

Question Click to View Answer
arr = ['onyx', 'wu tang', 'biggie']

Get the 'biggie' string from arr. Explain how arrays are ordered.

arr[2]
# OR
arr[-1]

Arrays are ordered collections of objects. Arrays are zero-indexed, meaning the first element is at position zero, the second is at position one, and so forth.

arr = [:cool, "freezing", -10, Object.new]

Explain how the arr array contains different types of objects.

The arr array contains a symbol (:cool), a string ("freezing"), an integer (-10) and a generic object. Arrays are an ordered collection of other objects and there are no restrictions on the types of objects that can be included in an array.

# Example #1:
my_array = [10, 20, 30]
my_array[0] = "bob"

# Example #2:
another_arr = [10, 20, 30]
another_arr.map {|num| num == 10 ? "bob" : num}

Example #1 and Example #2 both result in the ["bob", 20, 30] array. What is the key difference between the two examples?

Example #1 mutates my_array and Example #2 does not mutate another_arr. Mutating an array means changing it so it is no longer the same (i.e. deleting elements, adding new elements, etc.). The map() method creates a new array, so the another_arr is unchanged.

Identify the components of the following code (i.e. the method name, arguments, code block, etc.):

[1, 2, 3].map {|num| num ** 2}
[1, 2, 3] # an array object.

map() # a method that is built-in to the Array class of Ruby.

{|num| num ** 2} # a code block that is executed for each number in the array.  Blocks can only appear in argument lists and must be the last argument.  For now, just understand that code blocks are accepted by some methods and must be included as the last argument in the argument list.

Identify the components of the following code (i.e. the method name, arguments, and code block).

['a', 'b'].each do |letter|
  hangout = letter + ' bar'
  p hangout
end
['a', 'b'] # an array object.

each() # a method that is built-in to the Array class of Ruby.

#The following code is a multi-line code block:
do |letter|
  hangout = letter + ' bar'
  p hangout
end
colors = ['red', 'violet', 'blue']

Use the colors array to construct the following array:

[['red', 1], ['violet', 2], ['blue', 3]]
colors.map.with_index do |color, index|
  [color, index + 1]
end

# OR

result = []
colors.each_with_index do |color, index|
  result << [color, index  + 1]
end
result # now equals [['red', 1], ['violet', 2], ['blue', 3]]

Create an array of the numbers 1 though 100 (i.e. [1, 2, 3, ..., 99, 100]).

(1..100).to_a

(1..100) is a Range object. The to_a method is defined in the Range class to convert a range to an array.

Create an array of all the numbers between 1 and 100 that are divisible by both 3 and 5.

(1..100).to_a.select do |number|
  number % 3 == 0 && number % 5 == 0
end
fib = [0, 1]

Use fib to create the following array: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] Notice that these are the first ten numbers in the Fibonocci sequence and each number equal the sum of the prior two numbers.

while fib.length < 10
  fib << fib[-2] + fib[-1]
end

The last element of the fib array is accessed with fib[-1] and the second to last element of the fib array is accessed with fib[-2]. The << operator is used to add elements to the fib array, but the push() method could have been used instead.

blockbusters = [['will smith', 'i am legend'], ['brad pitt', 'fight club'], ['frodo', 'the hobbit']]

Use the blockbusters array to construct the following hash:

{"will smith" => "i am legend", "brad pitt" => "fight club", "frodo" => "the hobbit"}
Hash[blockbusters]

# OR

result = {}
blockbusters.each do |actor, movie|
  result[actor] = movie
end
result # hash is now populated

The actor and movie block variables correspond with the first and second element of sub-arrays in the blockbusters array The block variables make the code significantly more readable than regular array indexing:

result = {}
blockbusters.each do |sub_array|
  result[sub_array[0]] = sub_array[1]
end
result # same result, but less readable code
players = [['r', 'kelly'], ['50', 'cent'], ['miley', 'cyrus']]

Use the players array to construct the following array: ["kelly", "cent", "cyrus"]

players.map do |_, last_name|
  last_name
end

The first_name block variable is not used, so the convention is to name this variable . This code would also work, but it is extraneous to define the firstname block variable if it is never used.

players.map do |first_name, last_name| last_name end

numbers = [1, 2, 3, 4]

Sum all the elements in the numbers array.

result = 0
numbers.each do |number|
  result += number
end
result # equals 10

# OR

numbers.inject(0) do |sum, number|
  sum += number
  sum
end

The inject() method keeps track of the running total in the sum block variable. For each iteration, the number is added to the sum and the sum is returned. This video demonstrates how inject() works very well: http://vimeo.com/51579832

nums = [1, 2, 3]
letters = ['a', 'b', 'c']

Use nums and letters to construct the following array:

[[1, "a"], [1, "b"], [1, "c"], [2, "a"], [2, "b"], [2, "c"], [3, "a"], [3, "b"], [3, "c"]]
result = []
nums.each do |num|
  letters.each do |letter|
    result << [num, letter]
  end
end
result # equals [[1, "a"], [1, "b"], [1, "c"], [2, "a"], [2, "b"], [2, "c"], [3, "a"], [3, "b"], [3, "c"]]

# OR

nums.inject([]) do |memo, num|
  letters.each do |letter|
    memo << [num, letter]
    memo
  end
  memo
end

Create the following array:

[1, 10, 100, 1_000, 10_000, 100_000, 1_000_000]

Notice that every element of the array is equal to the previous element times ten.

7.times.map { |i| 10 ** i }
numbers = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
suits = ['spades', 'hearts', 'diamonds', 'clubs']

Use numbers and suits to construct the following array (represents the 52 cards in a deck): [["2", "spades"], ["3", "spades"] ... ["K", "clubs"], ["A", "clubs"]]

result = []
suits.each do |suit|
  numbers.each do |number|
    result << [number, suit]
  end
end

# OR

suits.inject([]) do |memo, suit|
  numbers.each do |number|
    memo << [number, suit]
    memo
  end
  memo
end
music = [["blind melon", "no rain"], ["sublime", "40 oz to freedom"], ["damian marley", "jr gong"]]

Use the music array to construct the following hash:

{"blind melon" => "no rain", "sublime" => "40 oz to freedom", "damian marley" => "jr gong"}
result = {}
music.each do |band, song|
  result[band] = song
end

# OR

music.inject({}) do |memo, (band, song)|
  memo[band] = song
  memo
end

# OR

Hash[music]
fav_numbers = [1, 2, 3, 4, 10, 20, 33, 35]

Use fav_numbers to create the following array (all the even numbers):

[2, 4, 10, 20]
fav_numbers.select do |number|
  number.even?
end

# OR

fav_numbers.map do |number|
  number if number.even?
end.compact # way uglier than select()

The compact() method removes all the nil objects from an array.

Explain the difference between the following examples:

# Example #1:
[1, 2, 3, 4].select {|x| x.odd?}

# Example #2:
[1, 2, 3, 4].select! {|x| x.odd?}

Example 1 creates a new array with all the odd numbers from the [1, 2, 3, 4] array. Example #2 mutates the [1, 2, 3, 4] array by deleting all the numbers that are not odd. Inspect the following code:

arr = [1, 2, 3, 4]
arr.select {|x| x.odd?}
arr # still equals [1, 2, 3, 4]
arr.select! {|x| x.odd?}
arr # arr has been mutated and equals [1, 3]

What does the following code return?

y = []
x = Array.new()
y == x
true

y = [] creates a new instance of the Array class with syntactic sugar (i.e. shortcut syntax to make the code more concise and readable). x = Array.new() also creates a new instance of the Array class, but uses the traditional syntax. Arrays are just like any other class in Ruby.

What does the following code return?

text_editor = ["vim"]
nemesis = ["vim"]
text_editor == nemesis
true

The text_editor and nemesis arrays both contain a string with the same characters in the same order.

What does the following code return?

book = ["intelligent investor"]
great_book = ["intelligent investor"]
book.object_id == great_book.object_id
false

The book and great_book arrays have the same content, but are different instances of the Array class and therefore have different object_ids. Array equality comparisons in Ruby check if arrays have the same content in the same order, not if the arrays are the same exact object.

What does the following code return?

['a', 'b'] == ['b', 'a']
false

Arrays are ordered collections of objects (order is very important), so arrays with the same content in different orders are not considered equal.

Add a all_start_with_a? method to the Array class that returns true if every String element in an array starts with the letter "a".

["all", "in", "the", "family"].all_start_with_a? # should return false
["aardvark", "anteater"].all_start_with_a? # should return true
class Array
  def all_start_with_a?
    self.all? do |word|
      word[0] == "a"
    end
  end
end

Opening core library classes and adding custom methods is called "monkey patching".

What is the sum of all the numbers between 0 and 100 that are divisible by both 3 and 5?

(0..100).to_a.inject(0) do |memo, number|
  memo += number if number % 3 == 0 && number % 5 == 0
  memo
end

# OR

(0..100).to_a.select do |number|
  number % 3 == 0 && number % 5 == 0
end.inject do |memo, number|
  memo += number
  memo
end
first = ["cool", "busta", "odb"]
second = ["puffy", "cool", "busta"]

Create an array of all the elements that are in first, but not in second.

first - second # returns ["odb"]
first = ["cool", "busta", "odb"]
second = ["puffy", "cool", "busta"]

Create an array of all the elements that are in first and second with no duplicates.

(first + second).uniq

# OR

first + (second - first)

(second - first) provides the elements that are in second and not in first.

manly = ['batman', 'manbot', 'mace', 'tulip', 'nah man, nah']

Create an array of all elements in the manly array that contain the word "man". The return value should be:

["batman", "manbot", "nah man, nah"]
manly.grep /man/

# OR

manly.select {|word| word.match /man/ }
days = ['mon', 'tues', 'wed', 'thur', 'fri']

Create an array of the elements with indexes 0 and 2. The return value should be ['mon', 'wed'].

days.values_at(0, 2)

# OR

days.select.with_index do |_, index|
  [0, 2].include? index
end