2017-08-08 63 views
5

我有一个数组的数组,并希望将元素附加到子数组。 + =做我想要的,但我想明白为什么push不行。Ruby array + = vs push

行为我期望(以及与+ =作品):

b = Array.new(3,[]) 
b[0] += ["apple"] 
b[1] += ["orange"] 
b[2] += ["frog"] 

B => [[ “苹果”],[ “橙”],[ “蛙”]]

随着推我得到附加到每个子阵列的推元件(为什么?):

a = Array.new(3,[]) 
a[0].push("apple") 
a[1].push("orange") 
a[2].push("frog") 

一个=> [[ “苹果”, “橙”, “蛙”],[ “苹果”, “橙”, “青蛙”],[“苹果”,“橙色”,“青蛙”]]

对此非常感谢。

+0

不仅这个问题已经在[so]上被提出并回答了几十次,这个*确切的问题*,包括它的解决方案,在['Array :: new'] http://ruby-doc.org/core/Array.html#method-c-new-label-Common+gotchas)。 –

+0

没有错误的问题,但有错误的答案。这是我的第一个问题。我已经为Ruby编了2天(编码40年),创建了一些类来处理任何游戏(自我训练)的游戏。这是我通过文档找不到的第一个问题(是的,我错过了文档中的某些东西 - 我确信这绝不会发生在你身上)。我确实搜索了“ruby + = push”,还有其他一些人试图在这里找不到任何东西。 Eiko的慷慨精神是一个很好的指导,@Jorg。我相信你是一个很好的“休闲程序员”,你不必通过拖动noobs来证明它。 –

回答

9

这里的问题是b = Array.new(3, [])使用相同的对象对于所有的阵列单元基值:

b = Array.new(3, []) 
b[0].object_id #=> 28424380 
b[1].object_id #=> 28424380 
b[2].object_id #=> 28424380 

所以当你使用b[0].push,它添加项目“每个”子阵列,因为他们都是,实际上,在同一阵列。

那么为什么b [0] + = [“value”]有效?好了,看着红宝石文档:

元+ other_ary→new_ary

级联 - 返回由两个数组串联起来,以产生第三阵列建立了一个新的数组。

[ 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 

这意味着它会产生一个新的数组。结果,在数组上重复使用+ =会非常低效。

所以当你使用+=,它完全取代了数组,这意味着在b[0]数组不再一样b[1]b[2]

正如你可以看到:

b = Array.new(3, []) 
b[0].push("test") 
b #=> [["test"], ["test"], ["test"]] 
b[0].object_id #=> 28424380 
b[1].object_id #=> 28424380 
b[2].object_id #=> 28424380 
b[0] += ["foo"] 
b #=> [["test", "foo"], ["test"], ["test"]] 
b[0].object_id #=> 38275912 
b[1].object_id #=> 28424380 
b[2].object_id #=> 28424380 

如果你想知道如何保证每个数组初始化独特数组的数组时,你可以这样做是这样的:

b = Array.new(3) { [] } 

这个不同的语法可以让你传递一个代码块,它为每个单元格运行来计算它的原始值。由于该块针对每个单元格运行,因此每次都会创建一个单独的数组。

+1

非常感谢。这是我的第一个问题,我不知道如何将答案设置为“正确”。也感谢效率评论。我会留意的。顺便解答:'b = Array.new(3)''3.times {| i | b [i] = []}'(如果有更好的方法来“断开对象链接”,请让我)。 - 只是一个老c/C++/c#程序员教自己ruby :) –

+0

@DavidBunnell我很高兴帮助!如果你看这个答案的左上角,你应该看到一个复选标记(旁边的分数和上/下箭头进行投票)。如果您点击该复选标记,它会变成绿色,让每个人都知道这个答案适合您。欢迎来到stackoverflow和快乐的编码^ _^ – eiko

+0

@DavidBunnell也,我已经更新了我的答案用更加雄辩的方式来初始化数组。你在评论中提到的代码虽然相似,但! – eiko

0

这是因为在第二个代码部分中,您选择了子数组并推送到它,如果需要数组的数组,则需要将数组推送到主数组。

a = Array.new(3,[]) 
a.push(["apple"]) 
a.push(["orange"]) 
a.push(["frog"]) 

得到与第一个相同的结果。

编辑:我忘了提,因为你初始化空白阵列的方向是作为元素,你会在推元素的前面有三个空元素,

+2

这是不对的,并且忽略了问题的根源:'Array.new'的'[]'参数为所有条目创建一个* shared *数组。 – tadman