Rubyで配列を別の配列に追加して、多次元の結果にならないようにするにはどうすればよいですか?


474
somearray = ["some", "thing"]

anotherarray = ["another", "thing"]

somearray.push(anotherarray.flatten!)

期待した

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

6
ここであなたの期待が問題であると言うことは価値があります(あなたに悲しみを与えるのではなく、何度もあなたを噛むからです)。Rubyの配列(Perlの配列とは異なります)は、このようなコンテキストで自動的にフラット化されませ。これはバグではなく、機能です。
テレマコス

3
ri Array@flatten!なぜこの質問は非常に多くの票を得ているのですか?ドキュメントは明示的なArray#flatten! Flattenセルフです。変更が行われなかった場合(つまり、配列に
サブ

7
質問は、ユーザーにとって役立つ場合に賛成票を獲得します。最も単純な質問は、ほとんどの人に役立つので、最高の票を得ます。
ジギー

@yeyo、フラット化操作は無料だと思いませんか?
コンスタンティン

@Konstantin opは代替案を探したり、パフォーマンスの問題について話したりしていません。opは、そのflatten!ように機能しないために、彼または彼女が得られなかった結果を期待していました。最後に、質問は最適化問題ではなく論理問題を反映しています。詳細については、以下のpilcrowの回答を参照してください。
イェヨ2018

回答:


713

あなたは、実行可能なアイデアを持っているが、#flatten!間違った場所にある-あなたがオンにそれを使用することができますので、それは、その受信機を平ら[1, 2, ['foo', 'bar']][1,2,'foo','bar']

私はいくつかのアプローチを忘れてはいけませんが、あなたは連結することができます

a1.concat a2
a1 + a2              # creates a new array, as does a1 += a2

または先頭に追加/追加

a1.push(*a2)         # note the asterisk
a2.unshift(*a1)      # note the asterisk, and that a2 is the receiver

またはスプライス

a1[a1.length, 0] = a2
a1[a1.length..0] = a2
a1.insert(a1.length, *a2)

または追加して平坦化します:

(a1 << a2).flatten!  # a call to #flatten instead would return a new array

17
提示されたコードの何が問題であるかを実際に指摘した唯一の(私が確認できる5つのうちの1人)であることはよくできています。+1
マイクウッドハウス

53
concatの代わりにpushを使用すると、3番目の配列の作成が回避されるため、これは大きな配列に適しています。
ファットマン

8
私はアスタリスク付きのプッシュが大好きです。とてもエレガント。
orourkedd

14
連結@phatmann Array#concatで新しい配列、連結を割り当てないArray#+
cbliard

5
この答えが欠けている唯一のものは、各アプローチのベンチマーク比較です。+1!
Terra Ashley

206

+演算子を使うだけ!

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]

ここで配列クラスのすべてを読むことができます:http : //ruby-doc.org/core/classes/Array.html


15
ポスターは、2つの配列の和集合である新しい配列を作成するのではなく、既存の配列に連結する方法を知りたがっていました。
ファットマン

1
注:a+= b新しいアレイを作成します:c = a = [1,2] ; b = [3,4] ; a += b ; puts c #=> [1,2]
kbrock

1
@kbrock正解。大きな配列を扱う場合pushは、@ pilcrowで説明されている方法を確認する必要があります。
Joshua Pinter、2015

2
+=新しいオブジェクトを作成することを覚えておいてください。このような例では、[1, 2].each_with_object([]) { |number, object| object+=number }空の配列[]が返されます
Filip Bartuzi '06 / 11/15

1
追加するアイテムは配列でなければなりません
RousseauAlexandre

66

最もクリーンな方法は、Array#concatメソッドを使用することです。新しい配列は作成しません(同じことを行うが新しい配列を作成するArray#+とは異なります)。

ドキュメントから直接(http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-concat):

concat(other_ary)

other_aryの要素を自分自身に追加します。

そう

[1,2].concat([3,4])  #=> [1,2,3,4]  

Array#concatは、引数として渡された場合、多次元配列をフラット化しません。個別に処理する必要があります。

arr= [3,[4,5]]
arr= arr.flatten   #=> [3,4,5]
[1,2].concat(arr)  #=> [1,2,3,4,5]

最後に、corelib gem(https://github.com/corlewsolutions/corelib)を使用して、Rubyコアクラスに便利なヘルパーを追加できます。特に、連結を実行する前に多次元配列を自動的にフラット化するArray#add_allメソッドがあります。


1
通常は不変性を必要とするため、新しい配列を作成することをお勧めします。
vasilakisfil 2015

5
「通常は不変性を求めます」は正確ではありません。20年以上にわたるフルタイムのソフトウェア開発で、私はあらゆる種類のアレイとコレクションを毎日扱ってきました。場合によっては、既存の配列を変更します。新しいインスタンスを使用する必要がある場合があります。
Corlew Solutions、

35

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]

2
@Ikutyこれは私が見つけた最もエレガントなソリューション*です。ここで何が起こっているのか説明していただけますか?
Abhinay

@Abhinay platオペレーターは、配列を要素に分解して、最終行に1次元配列を作成します。
Omar Ali

[*a, *b]古いバージョンのRuby、つまり1.8.7では失敗します。そして、Rubyがその寿命を告げたいのと同じくらい、RHEL6はまだ維持されており、Ruby 1.8は非常に重要なターゲットバージョンになっています。
Otheus 2017年

1
私はそれがこの答えが得る-1を正当化するとは思わない。OPで言及されているルビバージョンはなく、回答で明示的に言及されているルビバージョンなので、... pre alpha 0.0.0.0.1以前のバージョンとの下位互換性が必要ですか?これは、ルビーのバージョンに応じて、優れたソリューションの1つです
Ludovic Kuty

1
この答えは[...array1, ...array2]、あなたができる非常に慣用的なJavaScript ES6に非常に「似ている」ことを指摘しておきます。splatルビの演算子はの*代わりになることを覚えておいてください...。覚えやすくなります
sandre89 2018

34

これを試してください、それはあなたの配列を組み合わせて重複を取り除きます

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

array3 = array1|array2

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

さらなるドキュメントは「Set Union」を見てください


これは、または、重複する要素のない配列を返します。これは、おそらく彼が求めていることを実行しない方法の例です。最初の配列の2つの「baz」が1つになり、「bar」になります。 2番目の配列には追加されません。array1 = ["foo"、 "bar"、 "baz"、 "baz"] array2 = ["foo1"、 "bar1"、 "bar"] array3 = array1 | array2 array3#=> ["foo"、 "bar "、" baz "、" foo1 "、" bar1 "]
ジョシュアチーク

またはさらに良い:array1 |= [ "foo1", "bar1" ] #=> [ "foo", "bar", "foo1", "bar1" ]
Joshua Pinter 2018

33

ここに2つの方法があります。この場合、最初の方法が新しい配列を割り当てることに注意してください(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"]

25
a = ["some", "thing"]
b = ["another", "thing"]

結果を追加baて保存するにはa

a.push(*b)

または

a += b

どちらの場合も、次のようにaなります。

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

ただし、前者の場合はの要素がb既存のa配列に追加され、後者の場合は2つの配列が連結されて結果がに格納されaます。


2
a.push(*b)はまったく同じではないことに注意してくださいa += b。前者は既存の配列に新しい要素を追加します。後者は、すべての要素を含む新しい配列を作成し、それをに割り当てaます。いずれかの追加メソッドの前にaa = arefを保存して、後でa調べるような場合は、違いを確認できますaa。前者の場合は、の新しい値で変化しa、後者の場合は変化しません。
Dave Hartnoll

20

(array1 + array2).uniq

この方法では、最初にarray1要素を取得します。重複はありません。


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

結果:

       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)

あなたが見ることができるように、配列が十分に大きいとき、エラーpush投げます:stack level too deep (SystemStackError)


8

本質的に、問題は「Rubyで配列を連結する方法」です。もちろん答えは使用することですconcat+ほぼすべての回答で述べたように。

問題に対する自然な拡張は、「Rubyで2D配列の行ごとの連結を実行する方法」です。「ruby concatenate matrixs」をググると、このSOの質問が最高の結果だったので、後世のためにその質問(答えはありませんが関連しています)への回答はここに残しておきましょう。


一部のアプリケーションでは、2つの2D配列を行方向に「連結」する場合があります。何かのようなもの、

[[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]]

8

それを行うためのちょうど別の方法。

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

flattenすべてを可能な限り再帰的に平坦化します。ネストされた配列でも。その結果、場合somearrayまたはanotherarrayネストされた配列が含まれている、彼らはあまりにも、平らに取得します。これは通常意図しない副作用です。
ハゲロ

5

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


効率についてはわかりませんが、これはRuby 1.8で機能します。一般的に、[*a] + [*b]作品
Otheus 2017年

それが"another" + "thing"期待通りに機能するとは思いません。
Alexis Wilke

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 

4

誰も言及していないことに驚いていますreduce。これは、配列の配列がある場合にうまく機能します。

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

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

これは重複を削除しませんが、

a|b

重複を削除します。


注:これにより、すべての内部配列も再帰的にフラット化されます。
Mirodinho

2

次のように、配列をプッシュまたは追加してから、それらを所定の位置にフラット化する方が簡単だと思います。

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"]

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.