2016-06-24 7 views
7

나는 array(1 and 2)이 있습니다. 어떻게하면 array3을 얻을 수 있습니까?루비 배열 교차점 (중복 포함)

array1 = [2,2,2,2,3,3,4,5,6,7,8,9] 

array2 = [2,2,2,3,4,4,4,4,8,8,0,0,0] 

array3 = [2,2,2,3,4,8] 

array1 & array2 반환 [2,3,4,8]하지만 나는 중복에 유지해야합니다. 샘플 어레이의 각 요소의 주파수를 얻기

+0

중복으로 두 배열의 같은 위치에있는 값을 의미합니까? – sahil

+1

나는'array3'에 3이 들어 있기 때문에 그가하지 않는다고 생각하지만, 값은'array1'과'array2'에 정렬되어 있지 않습니다. –

+0

결과의 요소 순서가 중요한지 여부와 최소 또는 최대 일치 개수가 필요한지, 즉 배열 비교 순서가 중요한지 여부를 지정해야합니다. –

답변

12
(array1 & array2).flat_map { |n| [n]*[array1.count(n), array2.count(n)].min } 
    #=> [2,2,2,3,4,8] 

단계 :

,515,
a = array1 & array2 
    #=> [2, 3, 4, 8] 

a (2)의 첫 번째 요소는 블록으로 전달하고, 블록 변수에 할당 : 행한다

n = 2 

상기 블록 계산 :

[2]*[array1.count(2), array2.count(2)].min 
    #=> [2]*[4,3].min 
    #=> [2]*3 
    #=> [2,2,2] 

너무 2[2,2,2]에 매핑됩니다. 계산은 a의 나머지 세 요소에 대해 비슷합니다. flat_map을 사용하고 있으므로 [2,2,2,3,4,8]을 반환합니다.

Enumerable#flat_mapEnumerable#map과 다른 점을 기억하는 데 어려움이 있습니까? flat_map 대신 map을 사용했다고 가정합니다. 배열 array1array2이 크고 효율성이 문제가되는 경우

[*[2, 2, 2], *[3], *[4], *[8]] 
    #=> [2, 2, 2, 3, 4, 8] 

, 우리는 조금 할 수 없었다 : 다음

a.map { |n| [n]*[array1.count(n), array2.count(n)].min } 
    #=> [[2, 2, 2], [3], [4], [8]] 

flat_map 그 배열의 각각의 앞에 플랫를 넣어 더 아무것도하지 O의 (N) 전처리 :

def cnt(arr) 
    arr.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 } 
end 

cnt1 = cnt(array1) 
    #=> {2=>4, 3=>2, 4=>1, 5=>1, 6=>1, 7=>1, 8=>1, 9=>1} 
cnt2 = cnt(array2) 
    #=> {2=>3, 3=>1, 4=>4, 8=>2, 0=>3} 

(array1 & array2).flat_map { |n| [n]*[cnt1[n], cnt2[n]].min } 
    #=> [2,2,2,3,4,8] 
+2

가장 좋은 답변은 여기까지입니다. (광산은 O (N)이고이 것은 최악의 경우 O (N²)이기 때문에 아직 없습니다.) – mudasobwa

+0

@mudasobwa, 좋은 지적. 나는 편집을했다. –

+0

효율적인 답변이지만 내 의견으로는 읽기가 쉽지 않습니다. 나는 OP가 프로그래밍에 익숙하지 않았으며 좀 더 친숙한 대답을하려고 노력했다. 나는 당신이 결코 생각하지 않아야한다고 생각합니다. – Tommyixi

1
array1 = [2,2,2,2,3,3,4,5,6,7,8,9] 
array2 = [2,2,2,3,4,4,4,4,8,8,0,0,0] 

a1, a2 = array1.dup, array2.dup # we’ll mutate them 

loop.with_object([]) do |_, memo| 
    break memo if a1.empty? || a2.empty? 
    e = a2.delete_at(a2.index(a1.shift)) rescue nil 
    memo << e if e 
end 
#⇒ [2,2,2,3,4,8] 
1
array1 = [2,2,2,2,3,3,4,5,6,7,8,9] 
    array2 = [2,2,2,3,4,4,4,4,8,8,0,0,0] 

: 그들은 다른 배열 여부에 존재하는 경우

a1_freq=Hash.new(0); a2_freq=Hash.new(0); dup_items=[]; 
    array1.each {|a| a1_freq[a]+=1 } 
    array2.each {|b| a2_freq[b]+=1 } 

마지막 요소를 비교한다. 그렇다면 두 샘플 배열에서 공통 요소의 최소 개수를 가져옵니다.

a1_freq.each {|k,v| a2_freq[k] ? dup_items+=[k]*[v,a2_freq[k]].min : nil} 
    #dup_items=> [2, 2, 2, 3, 4, 8] 
+1

['Hash # default_proc'] (http://ruby-doc.org/core-2.1.5/Hash.html#method-c-new)을 사용해보십시오 :'a1_freq = Hash.new {| h, k | (또는 디폴트 값'a1_freq = Hash.new (0)') 이상한 삼자를 피하십시오 :'array1.each {| a | h [k] = 0}' a1_freq [a] + = 1}'. – mudasobwa

+0

감사합니다. 0으로 초기화 할 수 있다는 것을 알지 못했습니다. – sahil

+1

매우 빠르고 매우 빠릅니다! 게시 한 후에 계산 해시를 만드는 아이디어를 추가했지만 지금까지 솔루션을 놓친 것 같습니다. –

0

이 조금 장황하지만, 값이 동일한 위치에있는 곳을 의미 가정 : 난 당신이 배열 3에 도착하는 방법을 단서가 없다 난 그냥 지적하고 싶었

def combine(array1, array2) 
    longer_array = array1.length > array2.length ? array1 : array2 

    intersection = [] 
    count = 0 
    longer_array.each do |item| 
     if array1 == longer_array 
      looped_array = array2 
     else 
      looped_array = array1 
     end 
     if item == looped_array[count] 
      intersection.push(item) 
     end 
     count +=1 
    end 
    print intersection 
end 


array_1 = [2,2,2,2,3,3,4,5,6,7,8,9] 
array_2 = [2,2,2,3,4,4,4,4,8,8,0,0,0] 


combine(array_1, array_2) 

때문에 세 배열에 대한 인덱스 위치 3 다릅니다

array_1[3] = 2 

array_2[3] = 3 

array_3[3] = 3 
0

내가 그런 식으로 예상되는 결과에 도달하려고합니다 :

array1, array2 = [array1, array2].sort_by(&:size) 
arr_copy = array2.dup 

array1.each.with_object([]) do |el, arr| 
    index = arr_copy.find_index(el) 
    arr << arr_copy.slice!(index) if index 
end 
# => [2, 2, 2, 3, 4, 8] 
3

이것은 재미 있습니다. Cary의 flat_map 솔루션은 특히 영리합니다.여기에 each_with_object에서 약간의 도움을 정기적으로 오래된 map를 사용하여 대체 한 줄의 :

# 
# we want to duplicate array2 since we'll be 
# mutating it to track duplicates  
#      \  array1  array2 
#      \  value  copy 
#       \   \ /
array1.each_with_object(array2.dup).map{|v,t| ... } 
#   |      /  
# Enumerator for array1 Iterate over    
# with a copy of array2 Enumerator with map 

: 여기 복잡성의

array1.each_with_object(array2.dup).map{|v,t| v if (l = t.index v) && t.slice!(l) }.compact 
#=> [2,2,2,3,4,8] 

대부분은 작업을 완료하는 데 충분한 정보 map를 제공하는 데 사용 인라인 체조를 포함

each_with_object을 사용하여 array1의 열거자를 제공 할 수 있습니다.이 열은 array2의 복사본에 대한 메서드 체인 액세스를 제공합니다. 그런 다음지도는 each_with_object 열거 자 (array1을 참조)를 반복하여 각 값을 로컬 변수 v에로드하고 배열 2 복사본을 로컬 변수 t에로드 할 수 있습니다. 거기에서 :

#    map the value IF... 
#    /it exists in  and we were able to 
#   /our array2 copy remove it from our copy 
#   /  |    | 
map{|v,t| v if (l = t.index v) && t.slice!(l) }.compact 
# | \   \        | 
# array1 \  \       dump nils 
# value array2 \ 
#   copy  load index position into temporary variable l 

우리는하는 array1의 각 값을 반복하고 (t를 통해) 값이 배열 2 내에 존재하는지 여부를 검색합니다. 존재하는 경우 array2의 사본에서 값의 첫 번째 발생을 제거하고 결과 배열의 값을 map으로 제거합니다.

값이 t 인 array2 사본에 단락 회로 보호로 사용하기 전에 검사를 수행하기 전에 t.slice!(t.index(v))을 사용하십시오. 우리는 또한 인덱스 값을 로컬 변수 l에 할당하는 인트 릭 트릭을 사용합니다 : (l = t.index v)이어서 t.slice!(l)의 부울 검사에서 l을 참조 할 수 있습니다.

마지막으로,이 방법론은 array1 값이 array2 내에 존재하지 않을 때마다 nil 값을 매핑하므로 결과가 compact 인 경우 nils가 제거됩니다.


궁금한 점은 지금까지 제시된 해결책에 대한 벤치 마크 테스트입니다. 첫째, 여기에 속도는 샘플 배열의 조작을 10 회 수행 클로킹 :

Cary:  1.050000 0.010000 1.060000 ( 1.061217) 
Cary+:  1.580000 0.010000 1.590000 ( 1.603645) 
Cam:   0.550000 0.010000 0.560000 ( 0.552062) 
Mudasobwa: 2.540000 0.050000 2.590000 ( 2.610395) 
Sergii:  0.660000 0.000000 0.660000 ( 0.665408) 
Sahil:  1.750000 0.010000 1.760000 ( 1.769624) 
#Tommy:  0.290000 0.000000 0.290000 ( 0.290114) 

우리가 교차의 높은 수준의 10000 개 정수를 개최 시험 배열을 확장하면 ...

array1 = array2 = [] 
10000.times{ array1 << rand(10) } 
10000.times{ array2 << rand(10) } 

루프를 100 번 반복하면 단순 루프 솔루션 (Sahil)이 자체를 구별하기 시작합니다. 캐리의 솔루션은 특히 전처리와, 잘 보유 : 배열 1/10 그러나 1000 개 정수와 교차낮은 정도와 크기에

    user  system  total  real 
Cary:  1.590000 0.020000 1.610000 ( 1.615798) 
Cary+:  0.870000 0.010000 0.880000 ( 0.879331) 
Cam:   6.680000 0.090000 6.770000 ( 6.838829) 
Mudasobwa: 6.740000 0.080000 6.820000 ( 6.898394) 
Sergii:  6.760000 0.100000 6.860000 ( 6.962025) 
Sahil:  0.740000 0.030000 0.770000 ( 0.785975) 
#Tommy:  0.430000 0.010000 0.440000 ( 0.446482) 

...

array1 = array2 = [] 
1000.times{ array1 << rand(10000) } 
1000.times{ array2 << rand(10000) } 

우리를 루프 10 배의 flat_map 솔루션은 ... 평평하게됩니다 우리가 (캐리 +) 전처리를 사용하는 경우를 제외하고 다음은

    user  system  total  real 
Cary:  135.400000 0.700000 136.100000 (137.123393) 
Cary+:  0.270000 0.010000 0.280000 ( 0.268255) 
Cam:   0.670000 0.000000 0.670000 ( 0.676438) 
Mudasobwa: 0.670000 0.010000 0.680000 ( 0.684088) 
Sergii:  0.660000 0.010000 0.670000 ( 0.673881) 
Sahil:  1.970000 2.130000 4.100000 ( 4.121759) 
#Tommy:  0.050000 0.000000 0.050000 ( 0.045970) 

는 벤치 마크와 요점이다 : https://gist.github.com/camerican/139463b4bd9e0fd89424377931042ce4

+2

재미있는 솔루션과 비교, 그리고 훌륭한 프레 젠 테이션. 이것에 대한 당신의 모든 노력에 찬사를 보냅니다. 내 솔루션의 변형을 "전처리"와 함께 벤치 마크에 추가 할 수 있습니까? –

+1

'Cary +'에서 flat_map w/preprocessing을 포함하도록 테스트가 업데이트되었습니다. 여분의 오버 헤드는 100,000x 테스트에서 불이익을 받지만 큰 어레이에서는 많은 도움이됩니다. 나는 테스트와 요지를 연결했다. – Cam

+0

@ Tommyixi는 그의 Wheaties를 먹고 있습니다. –