Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Basic Array Iteration in Ruby

Tags:

arrays

ruby

What's a better way to traverse an array while iterating through another array? For example, if I have two arrays like the following:

names = [ "Rover", "Fido", "Lassie", "Calypso"]
breeds = [ "Terrier", "Lhasa Apso", "Collie", "Bulldog"]

Assuming the arrays correspond with one another - that is, Rover is a Terrier, Fido is a Lhasa Apso, etc. - I'd like to create a dog class, and a new dog object for each item:

class Dog
  attr_reader :name, :breed

  def initialize(name, breed)
    @name = name
    @breed = breed
  end
end

I can iterate through names and breeds with the following:

index = 0

names.each do |name|
  Dog.new("#{name}", "#{breeds[index]}")
  index = index.next
end

However, I get the feeling that using the index variable is the wrong way to go about it. What would be a better way?

like image 611
michaelmichael Avatar asked Apr 15 '10 20:04

michaelmichael


People also ask

What does .each do in Ruby?

The each() is an inbuilt method in Ruby iterates over every element in the range. Parameters: The function accepts a block which specifies the way in which the elements are iterated. Return Value: It returns every elements in the range.

What is iteration in Ruby?

“Iterators” is the object-oriented concept in Ruby. In more simple words, iterators are the methods which are supported by collections(Arrays, Hashes etc.). Collections are the objects which store a group of data members. Ruby iterators return all the elements of a collection one after another.

How do you iterate an array in Ruby?

Ruby each Method To iterate over an array in Ruby, use the . each method. It is preferred over a for loop as it is guaranteed to iterate through each element of an array.


1 Answers

dogs = names.zip(breeds).map { |name, breed| Dog.new(name, breed) }

Array#zip interleaves the target array with elements of the arguments, so

irb> [1, 2, 3].zip(['a', 'b', 'c'])
 #=> [ [1, 'a'], [2, 'b'], [3, 'c'] ]

You can use arrays of different lengths (in which case the target array determines the length of the resulting array, with the extra entries filled in with nil).

irb> [1, 2, 3, 4, 5].zip(['a', 'b', 'c'])
 #=> [ [1, 'a'], [2, 'b'], [3, 'c'], [4, nil], [5, nil] ]
irb> [1, 2, 3].zip(['a', 'b', 'c', 'd', 'e'])
 #=> [ [1, 'a'], [2, 'b'], [3, 'c'] ]

You can also zip more than two arrays together:

irb> [1,2,3].zip(['a', 'b', 'c'], [:alpha, :beta, :gamma])
 #=> [ [1, 'a', :alpha], [2, 'b', :beta], [3, 'c', :gamma] ]

Array#map is a great way to transform an array, since it returns an array where each entry is the result of running the block on the corresponding entry in the target array.

irb> [1,2,3].map { |n| 10 - n }
 #=> [ 9, 8, 7 ]

When using iterators over arrays of arrays, if you give a multiple parameter block, the array entries will be automatically broken into those parameters:

irb> [ [1, 'a'], [2, 'b'], [3, 'c'] ].each { |array| p array }
[ 1, 'a' ]
[ 2, 'b' ]
[ 3, 'c' ]
#=> nil
irb> [ [1, 'a'], [2, 'b'], [3, 'c'] ].each do |num, char| 
...>   puts "number: #{num}, character: #{char}" 
...> end
number 1, character: a
number 2, character: b
number 3, character: c
#=> [ [1, 'a'], [2, 'b'], [3, 'c'] ]

Like Matt Briggs mentioned, #each_with_index is another good tool to know about. It iterates through the elements of an array, passing a block each element in turn.

irb> ['a', 'b', 'c'].each_with_index do |char, index| 
...>   puts "character #{char} at index #{index}"
...> end
character a at index 0
character b at index 1
character c at index 2
#=> [ 'a', 'b', 'c' ]

When using an iterator like #each_with_index you can use parentheses to break up array elements into their constituent parts:

irb> [ [1, 'a'], [2, 'b'], [3, 'c'] ].each_with_index do |(num, char), index| 
...>   puts "number: #{num}, character: #{char} at index #{index}" 
...> end
number 1, character: a at index 0
number 2, character: b at index 1
number 3, character: c at index 2
#=> [ [1, 'a'], [2, 'b'], [3, 'c'] ]
like image 73
rampion Avatar answered Nov 07 '22 16:11

rampion