【问题标题】:Difference between `+=` and `<<` inside a block for `each_with_object``each_with_object`的块内`+=`和`<<`之间的区别
【发布时间】:2016-02-09 13:45:50
【问题描述】:

我必须更新一个数组,并且我在传递给Array#each_with_object 的块内的不同代码运行中使用了+=&lt;&lt;

代码 1

(1..5).each_with_object([]) do |i, a|
  puts a.inspect
  a += [i]
end

输出:

[]
[]
[]
[]
[]

代码 2

(1..5).each_with_object([]) do |i, a|
  puts a.inspect
  a << [i]
end

输出:

[]
[1]
[1,2]
[1,2,3]
[1,2,3,4]

+= 运算符不会更新原始数组。为什么?我在这里错过了什么?

【问题讨论】:

  • 不是Array#each_with_object。接收者是一个范围。

标签: arrays ruby iterator immutability


【解决方案1】:

each_with_object中,所谓的memo对象在迭代中很常见。您需要修改该对象才能做一些有意义的事情。 += 运算符是+ 和赋值的语法糖,它不会修改接收者,因此迭代没有效果。如果你使用&lt;&lt;push之类的方法,就会生效。

另一方面,在inject中,所谓的memo对象就是block的返回值,不需要修改对象,但是需要返回自己想要的值供下次使用迭代。

【讨论】:

  • 从 Jorg 的回答中,我了解到我在每次循环运行中通过 + 创建新数组效率低下。但是,我将结果数组分配给 memo 对象......它不应该更新备忘录对象。相反,它会创建一个与memo 对象同名的新数组,而不是更新实际的memo 对象。
  • @HariShankar inject 就是这样。
【解决方案2】:

我很清楚 += 运算符没有更新原始数组。为什么?

因为the documentation 这么说(强调我的):

ary + other_arynew_ary

Concatenation — 返回一个 new 数组,该数组通过将两个数组连接在一起生成一个 第三个 数组。

[ 1, 2, 3 ] + [ 4, 5 ]    #=> [ 1, 2, 3, 4, 5 ]
a = [ "a", "b", "c" ]
c = a + [ "d", "e", "f" ]
c                         #=> [ "a", "b", "c", "d", "e", "f" ]
a                         #=> [ "a", "b", "c" ]

注意

x += y

相同
x = x + y

这意味着它会生成一个数组。因此,在数组上重复使用 += 可能会非常低效。

另见#concat

&lt;&lt;比较

ary &lt;&lt; objary

Append——将给定对象推到 this 数组的末尾。此表达式返回数组本身,因此可以将多个追加链接在一起。

[ 1, 2 ] << "c" << "d" << [ 3, 4 ]
        #=>  [ 1, 2, "c", "d", [ 3, 4 ] ]

Array#+ 的文档清楚地表明返回了一个 new 数组(实际上不少于四次)。这与 Ruby 中 + 方法的其他用途一致,例如Bignum#+Fixnum#+Complex#+Rational#+Float#+Time#+String#+BigDecimal#+Date#+Matrix#+Vector#+Pathname#+Set#+URI::Generic#+

【讨论】:

    猜你喜欢
    • 2012-09-02
    • 2014-05-20
    • 1970-01-01
    • 1970-01-01
    • 2015-01-11
    • 2011-06-18
    • 2017-08-14
    • 2011-07-19
    • 2011-05-05
    相关资源
    最近更新 更多