3

VERY new to Ruby and coding in general. I'm trying to loop through two dimensional arrays but can't figure it out. Here's what I have:

--Use a loop to print out each person on separate lines with their alter egos.

--Bruce Wayne, a.k.a. Batman

people = [ ["Bruce", "Wayne", "Batman"], ["Selina", "Kyle", "Catwoman"], ["Barbara", "Gordon", "Oracle"], ["Terry", "McGinnis", "Batman Beyond"] ] index = people[0][0] first_name = people[0][0] last_name = people[0][1] hero_name = people[0][2] 4.times do puts first_name + " " + last_name + "," " " + "a.k.a" " " + hero_name index = index + 1 end 

It does print the first line but then raises an error:

Bruce Wayne, a.k.a Batman # `+': no implicit conversion of Integer into String (TypeError) 
1
  • 1
    "," " " – I consider that advanced Ruby ;-) Commented May 31, 2018 at 15:11

3 Answers 3

7

In ruby we don’t use loops by index, like for and family; instead we iterate on collections:

people = [["Bruce", "Wayne", "Batman"], ["Selina", "Kyle", "Catwoman"], ["Barbara", "Gordon", "Oracle"], ["Terry", "McGinnis", "Batman Beyond"]] people.each do |first, last, nick| puts "#{first} #{last}, a.k.a #{nick}" end 

or

people.each do |first_last_nick| *first_last, nick = first_last_nick puts [first_last.join(' '), nick].join(', a.k.a ') end 
Sign up to request clarification or add additional context in comments.

2 Comments

Do we concatenate strings via + in Ruby? ;-)
@Stefan copy-paste is a pure evil :) I always do join as in the second example, to handle nils with compact instead of silly ifs. Fixed btw.
2

Your code produces error because you assign a String to index

index = people[0][0] 

and then you use it to count with

index = index + 1 

You could have used

index = 0 

and

index += 1 

A more Rubyesque way would be to enumerate the array and print it like this

people.each do |person| puts "#{person.first} #{person[1]}, a.k.a #{person.last}" end 

Which gives

Bruce Wayne, a.k.a Batman Selina Kyle, a.k.a Catwoman Barbara Gordon, a.k.a Oracle Terry McGinnis, a.k.a Batman Beyond 

Storing the parts in a variable improves readability but lenghtens the code which in turn diminishes readability, the choice is yours..

As an alternative you could name the indices or decompose like mudasobwa suggests.

Firstname, Lastname, Nickname = 0, 1, 2 people.each do |person| puts "#{person[Firstname]} #{person[Lastname]}, a.k.a #{person[Nickname]}" end 

5 Comments

Ever more Rubyesque would be to decompose person instead of using indices :)
@mudasobwa suggested people.each do |fn, ln, hn| instead of indices.
@mudasobwa yep, is better, I like yours more, BTW I used indices OR decompose, so I also changed 'The most' in 'A more' :)
Good explanation. Another problem is that index is never used in the OP's code to access the array so it would have produced the same output 4 times.
@mudasobwa even more Rubyesque would be to build a Person object that knew how to present itself and a People class to contain them :) (and a Soylent Green factory to decompose them)
0

For your code to work:

4.times do |character| puts people[character][0] + " " + people[character][1] + "," " " + "a.k.a" " " + people[character][2] end 

But iterating in ruby is done as answered by others. This is a version using a block {} instead:

people = [["Bruce", "Wayne", "Batman"], ["Selina", "Kyle", "Catwoman"], ["Barbara", "Gordon", "Oracle"], ["Terry", "McGinnis", "Batman Beyond"]] people.each { |character| puts "#{character [0]}, a.k.a #{character [1]} #{character [2]}" } #=> Bruce, a.k.a Wayne Batman #=> Selina, a.k.a Kyle Catwoman #=> Barbara, a.k.a Gordon Oracle #=> Terry, a.k.a McGinnis Batman Beyond 

In general to loop through nested arrays:

people.each do |character| character.each do |name| puts name end end 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.