在Ruby中如何将一个数组添加到另一个数组而不产生多维结果?

570

我尝试了:

somearray = ["some", "thing"]
anotherarray = ["another", "thing"]
somearray.push(anotherarray.flatten!)

我原本期望

["some", "thing", "another", "thing"]

但实际得到的是

["some", "thing", nil]

6
值得一提的是(不是为了责备你,而是因为这会反复困扰你),你的期望值是问题所在。Ruby数组(与Perl中的数组不同)在这种情况下不会自动展开。这不是一个bug,而是一个特性。 - Telemachus
4
为什么这个问题得到了这么多投票?文档已经明确说明Array#flatten!是“原地”将数组压平。如果没有进行修改(即数组不包含子数组),则返回nil。 - yeyo
14
如果问题对用户有用,它们会得到赞同。最简单的问题获得最多的赞同,因为它们对大多数人都有帮助。 - Ziggy
@yeyo,你不觉得展平操作是免费的吗? - Konstantin
@Konstantin op并不是在寻找替代方案或讨论性能问题,op期望得到一个结果,但由于flatten!的工作方式不同,所以没有得到。最后,这个问题反映了一个逻辑问题而不是一个优化问题。请参见下面pilcrow的答案获取更多信息。 - yeyo
@yeyo,实际问题标题与问题标题并不完全相关。我认为OP实际上想要将一个数组添加到另一个数组中,因此我认为值得向他和所有新手澄清dos和donts。你知道,SO问题标题在SE中有很大的权重;) - Konstantin
18个回答

10

另一种做法而已。

[somearray, anotherarray].flatten
=> ["some", "thing", "another", "thing"]

flatten尽可能地递归地将所有内容压平,甚至包括嵌套的数组。因此,如果somearrayanotherarray包含嵌套的数组,它们也会被压平。这是一个通常不打算发生的副作用。 - hagello

8
基本上,问题是“如何在Ruby中连接数组”。自然的答案是使用concat+,几乎每个答案都提到了这一点。
对问题的自然扩展将是“如何在Ruby中执行二维数组的逐行连接”。当我谷歌搜索“ruby concatenate matrices”时,这个SO问题是排名最高的结果,所以我想在这里留下我的答案,以供后人参考。
在某些应用程序中,您可能希望按行“连接”两个二维数组。类似于:
[[a, b], | [[x],    [[a, b, x],
 [c, d]] |  [y]] =>  [c, d, y]]

这有点像“增广”矩阵。例如,我使用了这种技术来创建一个单一的邻接矩阵来代表一堆较小的矩阵中的图形。如果不采用这种技术,我将不得不以可能出错或让人沮丧的方式迭代组件。例如,我可能需要使用each_with_index。相反,我结合使用zipflatten,如下所示:
# given two multi-dimensional arrays that you want to concatenate row-wise
m1 = [[:a, :b], [:c, :d]]
m2 = [[:x], [:y]]

m1m2 = m1.zip(m2).map(&:flatten)
# => [[:a, :b, :x], [:c, :d, :y]]

7
somearray = ["some", "thing"]
anotherarray = ["another", "thing"]
somearray + anotherarray # => ["some", "thing", "another", "thing"]
somearray.concat anotherarray # => ["some", "thing", "another", "thing"]
somearray.push(anotherarray).flatten # => ["some", "thing", "another", "thing"]
somearray.push *anotherarray # => ["another", "thing", "another", "thing"]
 

5
如果新数据可以是数组或标量,并且您希望防止新数据如果是数组则嵌套,那么展开运算符非常棒!它返回一个标量用于标量,对于数组则返回未打包的参数列表。
1.9.3-p551 :020 > a = [1, 2]
 => [1, 2] 
1.9.3-p551 :021 > b = [3, 4]
 => [3, 4] 
1.9.3-p551 :022 > c = 5
 => 5 
1.9.3-p551 :023 > a.object_id
 => 6617020 
1.9.3-p551 :024 > a.push *b
 => [1, 2, 3, 4] 
1.9.3-p551 :025 > a.object_id
 => 6617020 
1.9.3-p551 :026 > a.push *c
 => [1, 2, 3, 4, 5] 
1.9.3-p551 :027 > a.object_id
 => 6617020 

5
a = ['a', 'b']
b = ['c', 'd']
arr = [a, b].flatten

这不会删除重复项,但是

a|b

删除重复项。


注意:这将递归地展平所有内部数组。 - Mirodinho

5

我很惊讶没有人提到reduce,当你有一个数组的数组时,它可以很好地工作:

lists = [["a", "b"], ["c", "d"]]
flatlist = lists.reduce(:+)  # ["a", "b", "c", "d"]

4

somearray = ["一些", "东西"]

anotherarray = ["另一些", "东西"]

somearray + anotherarray


3

我发现将数组推入或添加到另一个数组中,然后在原地展平它们更容易,就像这样:

somearray = ["some", "thing"]
anotherarray = ["another", "thing"]
somearray.push anotherarray # => ["some", "thing", ["another", "thing"]]
#or
somearray << anotherarray # => ["some", "thing", ["another", "thing"]]
somearray.flatten!  # => ["some", "thing", "another", "thing"]
somearray # => ["some", "thing", "another", "thing"]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接