【问题标题】:Looping and appending hashes to an array循环并将哈希附加到数组
【发布时间】:2014-01-09 10:09:21
【问题描述】:

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

[
  {"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 内的数字?

【问题讨论】:

  • 使用 array &lt;&lt; hash.dup 而不是 array &lt;&lt; hash 因为您在这里添加的只是对哈希的引用,而不是哈希本身。
  • 我会使用(1..6).each_cons(2).map { |a, b| { start: a, end: b } }

标签: ruby


【解决方案1】:

这是因为哈希是可变的。如果你有foo = {"start" =&gt; 1},并且做foo["start"] += 1,那么foo仍然指向同一个哈希,尽管它被修改为{"start" =&gt; 2}。它不会更改参考。如果你在一个数组中有同一个对象的多个副本,并且更改修改其中一个,那么它们都将被修改。

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

【讨论】:

  • 很好的答案。非常简短,并解释了结果背后的机制。
【解决方案2】:

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

foo = 1
array = []

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

【讨论】:

  • 这根本不能回答问题。
【解决方案3】:

用途:

array << hash.dup

代替:

array << hash

因为您在这里添加的只是对哈希的引用,而不是哈希本身。

【讨论】:

    【解决方案4】:

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

    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 变量保存对对象的引用和 = 操作符的副本 参考文献。此外,像 a += b 这样的自赋值实际上是 转换为 a = a + b。因此,建议您了解 是否在某个操作中您实际上是在创建一个新对象 或修改现有的。

    例如,string

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-28
      • 1970-01-01
      • 2020-07-24
      • 2016-02-08
      • 2012-09-03
      • 2021-05-06
      • 1970-01-01
      相关资源
      最近更新 更多