循环并附加散列到数组

时间:2014-01-09 10:09:21

标签: ruby

我想创建一个像这样的哈希数组:

[
  {"start"=>1, "end"=>2},
  {"start"=>2, "end"=>3},
  {"start"=>3, "end"=>4},
  {"start"=>4, "end"=>5},
  {"start"=>5, "end"=>6}
]

当我尝试这段代码时:

foo = 1
bar = 2
hash = {}
array = []
5.times do
  hash['start'] = foo
  hash['end'] = bar
  array << hash
  foo += 1
  bar += 1
end

hash值在array内更改,同时向其添加循环和哈希值。 array成为:

[
  {"start"=>5, "end"=>6},
  {"start"=>5, "end"=>6},
  {"start"=>5, "end"=>6},
  {"start"=>5, "end"=>6},
  {"start"=>5, "end"=>6}
]

为什么会在以下情况发生:

foo = 1
array = []
5.times do
  array << foo
  foo += 1
end
array # => [1, 2, 3, 4, 5]

在循环期间不会更改array内的数字?

4 个答案:

答案 0 :(得分:3)

这是因为哈希是可变的。如果您有foo = {"start" => 1},并执行foo["start"] += 1,那么foo仍指向相同的哈希,尽管它已修改为{"start" => 2}。它不会改变参考。如果你在一个数组中有这个相同对象的多个副本并更改其中一个,那么所有这些副本都将被修改。

另一方面,数字不可变;如果您有foo = 1,并且foo += 1,那么foo现在将指向2,这是与1不同的对象。

答案 1 :(得分:2)

您每次都可以创建一个新哈希。

foo = 1
array = []

5.times do
  array << { 'start' => foo, 'end' => foo + 1 }
  foo += 1
end

答案 2 :(得分:1)

使用:

array << hash.dup

而不是:

array << hash

因为你在这里添加了对hash的引用,而不是hashs本身。

答案 3 :(得分:1)

您应该更改代码以在每次循环迭代中创建新哈希:

foo = 1
bar = 2
array = []
5.times do
  hash = {}
  hash['start'] = foo
  hash['end'] = bar
  array << hash
  foo += 1
  bar += 1
end
puts array

否则,您总是更改同一个对象,这就是您以与数组元素相同的哈希结束的原因。

作为关于主题的快速文献来自here

  

Ruby变量保存对象的引用和=运算符副本   参考文献。此外,实际上是自我分配,例如+ = b   翻译成a = a + b。因此,建议您注意   是否在某个操作中,您实际上是在创建一个新对象   或修改现有的。

     

例如,字符串&lt;&lt; “另一个”比字符串+ =“另一个”更快   (没有额外的对象创建),所以你最好使用任何   类定义的更新方法(如果这是你的意图),如果是的话   存在。但是,请注意所有其他变量的“副作用”   引用同一个对象:

        a = 'aString'
        c = a
        a += ' modified using +='
        puts c    # -> "aString"

        a = 'aString'
        c = a
        a << ' modified using <<'
        puts c    # -> "aString modified using <<"