1

I'm confused about the way an array is updated when I loop through it. Here's a made up example that shows the behaviour.

people = [{"name"=>"Edward", "age" =>"43", "height"=>"tallish"},
          {"name"=>"Ralph", "age" =>"40", "height"=>"medium heigth"},
          {"name"=>"George", "age" =>"35", "height"=>"very tall"},
          {"name"=>"Mark", "age" =>"25", "height"=>"short"}]
numbers = ["1","3","26"]
new_array = []

numbers.each do |number|
    people.each do |person|
        person["name"] = person["name"] +" "+ number
        new_array << person
    end
end

At the end of that new_array is

[{"name"=>"Edward 1 3 26", "age"=>"43", "height"=>"tallish"},
{"name"=>"Ralph 1 3 26", "age"=>"40", "height"=>"medium heigth"},
{"name"=>"George 1 3 26", "age"=>"35", "height"=>"very tall"},
{"name"=>"Mark 1 3 26", "age"=>"25", "height"=>"short"},
{"name"=>"Edward 1 3 26", "age"=>"43", "height"=>"tallish"},
{"name"=>"Ralph 1 3 26", "age"=>"40", "height"=>"medium heigth"},
{"name"=>"George 1 3 26", "age"=>"35", "height"=>"very tall"},
{"name"=>"Mark 1 3 26", "age"=>"25", "height"=>"short"},
{"name"=>"Edward 1 3 26", "age"=>"43", "height"=>"tallish"},
{"name"=>"Ralph 1 3 26", "age"=>"40", "height"=>"medium heigth"},
{"name"=>"George 1 3 26", "age"=>"35", "height"=>"very tall"},
{"name"=>"Mark 1 3 26", "age"=>"25", "height"=>"short"}]

Each person appears three times, which I what I expected and wanted. BUT their name is the same each time. I expected name to be "Edward 1" the first time, then "Edward 1 3" and finally "Edward 1 3 26"

What's going on here? I thought the loop would append each separate hash onto new_array, rather than 3 all the same.

2
  • What output do you really want? There may be a simple non-iterative solution. Commented Apr 23, 2012 at 13:18
  • @Mark Thomas - I really want each hash with the name element changed several times. Commented Apr 23, 2012 at 13:34

2 Answers 2

1

people.each is providing you with a reference to each entry in people, so when you do person["name"] =... you're modifying the original array.

Try this:

numbers.each do |number|
    people.each do |person|
        new_person = person.dup
        new_person["name"] << " " + number
        new_array << new_person
    end
end
Sign up to request clarification or add additional context in comments.

5 Comments

new_array still ends up the same as before! I guess now new_person is a reference which gets updated.
...huh. I was not expecting that. I'll try to dig a bit further - this really should be possible.
See megas' answer - you just put the .dup to early
But his answer will still edit the original people array... surely?
Sorry, my question can't have been clear - I'm not particularly bothered about the original array, but what I get in new_array.
0

You can convert your code a little bit to see the process

numbers.each do |number|
    people.each do |person|
        person["name"] = person["name"] +" "+ number
        new_array << person
        puts person["name"]
    end
end

You will get this result:

Edward 1
...
Edward 1 3
...
Edward 1 3 26
...

As you can see the algorithm works almost as you expected. But person["name"] is reference to only one object(string), that's why the final result has the last string Edward 1 3 26

EDIT: To get your what you wanted you should create new object every time

numbers.each do |number|
  people.each do |person|
    person["name"] = person["name"] +" "+ number
    new_array << person.dup
  end
end

Don't forget reinitialize the people variable because this expression

person["name"] = person["name"] +" "+ number

modifies the people variable.

1 Comment

Thanks for the explanation, but how do I get what I wanted - an array with the different names?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.