Ruby에서 다른 배열에 배열을 어떻게 추가하고 다차원 결과로 끝나지 않습니까?


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

anotherarray = ["another", "thing"]

somearray.push(anotherarray.flatten!)

기대했다

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

6
여기에 당신의 기대가 문제라고 말할 가치가 있습니다 (슬픔을주지 말고 계속해서 물릴 것이기 때문에). Ruby 배열 (Perl의 배열과 달리)은 이와 같은 상황에서 자동으로 전개 되지 않습니다 . 이것은 버그가 아닙니다. 기능입니다.
Telemachus

3
ri Array@flatten!왜이 질문이 너무 많은 표를 얻고 있습니까? 의사는 명시 적 Array#flatten! Flattens 자체 자리에 있습니다. 수정 사항이없는 경우 (예 : 배열에 하위 배열이 포함되지 않은 경우) nil을 반환합니다.
yeyo

7
사용자에게 유용한 질문은 공감을 얻습니다. 가장 간단한 질문은 대부분의 사람들에게 유용하기 때문에 가장 많은 찬사를받습니다.
Ziggy

@yeyo, 당신은 단순히 평평한 작업이 무료라고 생각하지 않습니까?
Konstantin

@Konstantin op는 대안을 찾거나 성능 문제에 대해 이야기하지 않고 op는 flatten!그렇게 작동하지 않기 때문에 얻을 수 없었던 결과를 기대하고있었습니다 . 마지막으로이 질문은 최적화 문제보다는 논리 문제를 반영합니다. 자세한 내용은 아래의 까마귀 답변을 참조하십시오.
yeyo

답변:


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
Mike Woodhouse

53
concat 대신 push를 사용하면 세 번째 배열을 만들 수 없으므로 큰 배열에 적합합니다.
phatmann 2016 년

8
나는 별표로 푸시를 좋아합니다. 매우 우아합니다.
orourkedd

14
@phatmann 연결 Array#concat은 새로운 배열을 할당하지 않습니다. 연결 Array#+
cbliard

5
이 답변에서 유일하게 누락 된 것은 각 접근법의 벤치 마크 비교입니다. +1!
Terra Ashley

205

당신은 +연산자를 사용할 수 있습니다 !

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
포스터는 기존 어레이에 연결하는 방법을 알고 싶어서 두 어레이를 통합 한 새 어레이를 만들지 않았습니다.
phatmann

1
참고 : a+= b새 배열을 만듭니다.c = a = [1,2] ; b = [3,4] ; a += b ; puts c #=> [1,2]
kbrock

1
@kbrock 맞습니다. 배열을 다루는 경우 push@pilcrow에 설명 된 방법 을보고 싶을 것 입니다.
Joshua Pinter

2
+=새로운 객체 를 생성 한다는 것을 기억하십시오 . 예를 들어 [1, 2].each_with_object([]) { |number, object| object+=number }빈 배열 []이 반환됩니다
Filip Bartuzi

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의 요소를 self에 추가합니다.

그래서

[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 핵심 클래스에 유용한 도우미를 추가 할 수 있습니다. 특히 concat을 실행하기 전에 다차원 배열을 자동으로 병합 하는 Array # add_all 메소드가 있습니다.


1
일반적으로 불변성을 원하므로 새 배열을 만드는 것이 좋습니다.
vasilakisfil

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 연산자는 배열을 요소로 분해하여 마지막 행에 단일 차원 배열을 만듭니다.
Omar Ali

[*a, *b]이전 버전의 루비, 즉 1.8.7에서는 실패합니다. 루비가 수명을 다하기를 원하는만큼 RHEL6은 계속 유지되므로 루비 1.8을 매우 중요한 대상 버전으로 만듭니다.
Otheus

1
나는 이것이 대답이 얻는 -1을 정당화한다고 생각하지 않는다. OP에서 언급 한 루비 버전이 없으며 답변에 명시 적으로 언급 된 루비 버전이 있으므로 이전 알파 0.0.0.0.1 버전과 호환되도록하고 싶습니까? 이것은 루비 버전에 따라 좋은 솔루션 중 하나입니다
Ludovic Kuty

1
이 답변은 당신이 할 수있는 매우 관용적 인 JavaScript ES6과 매우 유사하다는 [...array1, ...array2]것을 지적하기 위해 splat루비 의 연산자는 *대신에 기억할 것입니다 .... 기억하기 쉬워집니다
sandre89

34

이것을 시도하십시오, 그것은 중복을 제거하는 배열을 결합합니다

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

array3 = array1|array2

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

추가 문서는 "Set Union"을 참조하십시오.


이것은 또는 중복 요소가없는 배열을 반환합니다. 여기서 그가 요청한 것을 수행하지 않는 방법의 예입니다. 첫 번째 배열의 두 "baz"가 하나로 바뀌고 "bar" 두 번째 배열에는 추가되지 않습니다. array1 = [ "foo", "bar", "baz", "baz"] array2 = [ "foo1", "bar1", "bar"] array3 = array1 | array2 array3 # => [ "foo", "bar ","baz ","foo1 ","bar1 "]
Joshua Cheek

또는 더 나은 :array1 |= [ "foo1", "bar1" ] #=> [ "foo", "bar", "foo1", "bar1" ]
Joshua Pinter

33

두 가지 방법이 있습니다.이 경우 첫 번째 방법은 새 배열을 할당합니다 (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"]

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

추가하기 ba하고에 결과를 저장 a:

a.push(*b)

또는

a += b

두 경우 모두 다음과 a같습니다.

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

전자의 경우 b기존 a배열에 요소 가 추가되고 후자의 경우 두 배열이 함께 연결되어 결과가에 저장됩니다 a.


2
참고 a.push(*b)정확히 동일하지 않습니다 a += b. 전자는 새로운 배열을 기존 배열에 추가합니다. 후자는 모든 요소가 포함 된 새 배열을 만들고에 할당합니다 a. append 메소드 전에 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

본질적으로 문제는 "루비에서 배열을 연결하는 방법"입니다. 당연히 대답은 거의 모든 대답에서 언급 concat했거나 사용 +하는 것입니다.

이 질문에 대한 자연스러운 확장은 "루비에서 2D 배열의 행 단위 연결을 수행하는 방법"입니다. "ruby concatenate matrices"를봤을 때,이 SO 질문이 최고의 결과 였으므로 후손을 위해 그 질문에 대한 답을 남겨 두겠다고 생각했습니다.


일부 응용 프로그램에서는 두 개의 2D 배열을 행 단위로 "연결"할 수 있습니다. 같은 것

[[a, b], | [[x],    [[a, b, x],
 [c, d]] |  [y]] =>  [c, d, y]]

이것은 행렬을 "증강"하는 것과 같습니다. 예를 들어,이 기법을 사용하여 단일 인접 행렬을 만들어 여러 개의 작은 행렬에서 그래프를 나타냅니다. 이 기술이 없다면 오류가 발생하기 쉽고 생각하기 힘들었던 방식으로 구성 요소를 반복해야했습니다. 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]]

8

또 다른 방법입니다.

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

flatten재귀 적으로 가능한 한 모든 것을 평평하게 만듭니다. 심지어 중첩 배열. 결과적으로 중첩 배열이 포함 somearray되거나 anotherarray포함 된 경우 평면화됩니다. 이것은 일반적으로 의도하지 않은 부작용입니다.
hagello

5

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


효율성에 대해서는 잘 모르지만 Ruby 1.8에서 작동합니다. 일반적으로 [*a] + [*b]작품
Otheus

나는 그것이 "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"]

2

somearray = [ "some", "thing"]

anotherarray = [ "다른", "것" "

somearray + anotherarray

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.