如何在Ruby中将数组添加到另一个数组而不是最终得到多维结果?

ncv*_*cvn 450 ruby arrays multidimensional-array

somearray = ["some", "thing"]

anotherarray = ["another", "thing"]

somearray.push(anotherarray.flatten!)
Run Code Online (Sandbox Code Playgroud)

我期望

["some","thing","another","thing"]
Run Code Online (Sandbox Code Playgroud)

pil*_*row 680

你有一个可行的想法,但#flatten!它在错误的地方 - 它使接收器变平,所以你可以用它来[1, 2, ['foo', 'bar']]变成[1,2,'foo','bar'].

我无疑忘记了一些方法,但你可以连接:

a1.concat a2
a1 + a2              # creates a new array, as does a1 += a2
Run Code Online (Sandbox Code Playgroud)

前置/附加:

a1.push(*a2)         # note the asterisk
a2.unshift(*a1)      # note the asterisk, and that a2 is the receiver
Run Code Online (Sandbox Code Playgroud)

拼接:

a1[a1.length, 0] = a2
a1[a1.length..0] = a2
a1.insert(a1.length, *a2)
Run Code Online (Sandbox Code Playgroud)

追加和扁平:

(a1 << a2).flatten!  # a call to #flatten instead would return a new array
Run Code Online (Sandbox Code Playgroud)

  • 使用push而不是concat可以避免创建第三个数组,因此这对于大型数组来说是首选. (50认同)
  • 作为唯一一个(我能看到的5个)实际上已经指出所呈现的代码有什么问题的人做得很好.+1 (14认同)
  • @phatmann与[`Array#concat`](http://www.ruby-doc.org/core/Array.html#method-i-concat)的连接不会分配一个新的数组,与[`Array#+连接] `](http://www.ruby-doc.org/core/Array.html#method-i-2B) (14认同)
  • 我喜欢用星号推动.十分优雅. (8认同)
  • 这个答案唯一缺失的是每种方法的基准比较.+1! (5认同)

mic*_*moo 199

你可以使用+操作员!

irb(main):001:0> a = [1,2]
=> [1, 2]
irb(main):002:0> b = [3,4]
=> [3, 4]
irb(main):003:0> a + b
=> [1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)

您可以在此处阅读有关数组类的所有内容:http: //ruby-doc.org/core/classes/Array.html

  • 海报想要知道如何连接到现有数组,而不是创建一个两个数组联合的新数组. (11认同)
  • 记住`+ =`创建新对象.例如`[1,2] .each_with_object([]){| number,object | object + = number}`empty array` []`将被返回 (2认同)

Cor*_*ons 62

最干净的方法是使用Array#concat方法; 它不会创建一个新的数组(不像Array#+,它会做同样的事情,但创建一个新的数组).

直接来自文档(http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-concat):

CONCAT(other_ary)

将other_ary的元素追加到self.

所以

[1,2].concat([3,4])  #=> [1,2,3,4]  
Run Code Online (Sandbox Code Playgroud)

阵列#的concat如果它被传递作为参数将不会变平多维数组.您需要单独处理:

arr= [3,[4,5]]
arr= arr.flatten   #=> [3,4,5]
[1,2].concat(arr)  #=> [1,2,3,4,5]
Run Code Online (Sandbox Code Playgroud)

最后,您可以使用我们的corelib gem(https://github.com/corlewsolutions/corelib),它为Ruby核心类添加了有用的帮助程序.特别是我们有一个Array#add_all方法,它会在执行concat之前自动展平多维数组.

  • "你通常想要不变性"并不准确.在20多年的全职软件开发中,我每天都使用各种阵列和集合.有时您会修改现有阵列.有时您需要使用新实例. (4认同)

g00*_*0ne 34

试试这个,它会结合你的数组删除重复项

array1 = ["foo", "bar"]
array2 = ["foo1", "bar1"]

array3 = array1|array2
Run Code Online (Sandbox Code Playgroud)

http://www.ruby-doc.org/core/classes/Array.html

进一步的文档看看"Set Union"


Lud*_*uty 33

适用于Ruby版本> = 2.0但不适用于旧版本的简单方法:

irb(main):001:0> a=[1,2]
=> [1, 2]
irb(main):003:0> b=[3,4]
=> [3, 4]
irb(main):002:0> c=[5,6]
=> [5, 6]
irb(main):004:0> [*a,*b,*c]
=> [1, 2, 3, 4, 5, 6]
Run Code Online (Sandbox Code Playgroud)

  • @Ikuty这是迄今为止我找到的最优雅的解决方案,你能解释一下这里发生的问题吗? (2认同)
  • 我认为这不能证明这个答案得到的 -1 是合理的。OP 没有提到 ruby​​ 版本,答案中明确提到了 ruby​​ 版本,所以......你想向后兼容 alpha 0.0.0.0.1 之前的版本吗?这是很好的解决方案之一,具体取决于 ruby​​ 版本 (2认同)
  • 只是要指出这个答案与非常惯用的 JavaScript ES6 非常“相似”,您可以在其中执行 `[...array1, ...array2]`,只需记住 ruby​​ 中的 `splat` 运算符将是 `* ` 而不是 `...`。它更容易记住 (2认同)

Jos*_*eek 31

这里有两种方法,在这种情况下注意第一种方式分配一个新数组(转换为somearray = somearray + anotherarray)

somearray = ["some", "thing"]

anotherarray = ["another", "thing"]

somearray += anotherarray # => ["some", "thing", "another", "thing"]

somearray = ["some", "thing"]
somearray.concat anotherarray # => ["some", "thing", "another", "thing"]
Run Code Online (Sandbox Code Playgroud)


sli*_*000 20

(array1 + array2).uniq

这样您首先获得array1元素.你将不会重复.


sni*_*ets 17

a = ["some", "thing"]
b = ["another", "thing"]
Run Code Online (Sandbox Code Playgroud)

要追加ba并保存结果a

a.push(*b)
Run Code Online (Sandbox Code Playgroud)

要么

a += b
Run Code Online (Sandbox Code Playgroud)

无论哪种情况,都a变为:

["some", "thing", "another", "thing"]
Run Code Online (Sandbox Code Playgroud)

但在前一种情况下,将的元素b附加到现有a数组中,而在后一种情况下,将两个数组串联在一起并将结果存储在中a

  • 注意,“ a.push(* b)”与“ a + = b”并不完全相同。前者将新元素添加到现有数组中。后者创建一个包含所有元素的新数组,并将其分配给`a`。如果您执行类似“ aa = a”的操作将引用保存到`a`之前,则可以看到差异,然后再使用`app`方法。在前一种情况下,它会随着新值“ a”而变化,而在后一种情况下,它将保持不变。 (2认同)
  • 注意:@DaveHartnoll 指出的对于 `each_with_object` 的使用等来说“极其重要”。执行 `each_with_object([]) { |thing, result| result += [thing] }` 不起作用,而使用 `push` 方法却可以。 (2认同)

jul*_*lez 9

详细解释@ Pilcrow的答案对于大型数组唯一合适的答案是concat(+)因为它很快并且在循环内操作时不会分配新对象进行垃圾收集.

这是基准:

require 'benchmark'

huge_ary_1 = Array.new(1_000_000) { rand(5_000_000..30_000_00) }

huge_ary_2 = Array.new(1_000_000) { rand(35_000_000..55_000_00) }

Benchmark.bm do |bm|
  p '-------------------CONCAT ----------------'
  bm.report { huge_ary_1.concat(huge_ary_2) }

  p '------------------- PUSH ----------------'
  bm.report { huge_ary_1.push(*huge_ary_2)  }
end
Run Code Online (Sandbox Code Playgroud)

结果:

       user     system      total        real
"-------------------CONCAT ----------------"
  0.000000   0.000000   0.000000 (  0.009388)
"------------------- PUSH ----------------"
  example/array_concat_vs_push.rb:13:in `block (2 levels) in <main>': stack level too deep (SystemStackError)
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,使用push抛出错误:stack level too deep (SystemStackError)当阵列足够大时.


Zig*_*ggy 8

本质上,问题是"如何在Ruby中连接数组".当然,答案是使用concat+几乎每个答案中都提到.

这个问题的一个自然延伸是"如何在Ruby中执行2D数组的逐行连接".当我用Google搜索"ruby concatenate matrices"时,这个SO问题是最重要的结果,所以我想我会在这里为后代留下我的答案(未提出但相关的)问题.


在某些应用程序中,您可能希望逐行"连接"两个2D数组.就像是,

[[a, b], | [[x],    [[a, b, x],
 [c, d]] |  [y]] =>  [c, d, y]]
Run Code Online (Sandbox Code Playgroud)

这类似于"扩充"矩阵.例如,我使用这种技术创建一个单邻接矩阵来表示一堆较小矩阵中的图形.如果没有这种技术,我将不得不以一种可能容易出错或令人沮丧的方式迭代组件.例如,我可能不得不这样做each_with_index.相反,我将拉链扁平组合如下,

# 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]]
Run Code Online (Sandbox Code Playgroud)


Dat*_*att 8

这是另一种方式.

[somearray, anotherarray].flatten
=> ["some", "thing", "another", "thing"]
Run Code Online (Sandbox Code Playgroud)


小智 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"]
 
Run Code Online (Sandbox Code Playgroud)


sam*_*amg 5

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

  • 我不认为“另一个”+“东西”会按预期工作。 (3认同)

San*_*rya 5

如果新数据可能是数组或标量,并且您想防止新数据嵌套在数组中,则splat运算符非常棒!它为标量返回标量,并为数组返回解压缩的参数列表。

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 
Run Code Online (Sandbox Code Playgroud)


Sco*_*ttJ 5

我很惊讶没有人提到reduce,当你有一个数组数组时它效果很好:

lists = [["a", "b"], ["c", "d"]]
flatlist = lists.reduce(:+)  # ["a", "b", "c", "d"]
Run Code Online (Sandbox Code Playgroud)


Aus*_*ric 5

a = ['a', 'b']
b = ['c', 'd']
arr = [a, b].flatten
Run Code Online (Sandbox Code Playgroud)

这不会删除重复项,但是

a|b
Run Code Online (Sandbox Code Playgroud)

删除重复项。