簡體   English   中英

Ruby-數組交集(重復項)

[英]Ruby - array intersection (with duplicates)

我有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] ,但我需要保留重復項。

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

步驟:

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

a2 )的第一個元素傳遞到塊並分配給塊變量:

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有何不同? 假設我使用map而不是flat_map 然后

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

flat_map只不過在每個數組的前面放了一個小圖示:

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

如果數組array1array2很大並且效率是一個問題,我們可以做一些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]

這是一個有趣的事情。 卡里的flat_map解決方案特別聰明。 這是使用常規舊map並在each_with_object幫助下的另一種each_with_object

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提供足夠信息以完成任務的內聯體操:

 #
 # 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  

我們可以使用each_with_object為array1提供一個枚舉數,該枚舉數還使我們的方法鏈可以訪問array2的副本。 然后,Map可以遍歷each_with_object枚舉器(引用array1),將每個值加載到局部變量v並將我們的array2復制到局部變量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的每個值並搜索該值是否存在於array2中(通過t )。 如果存在,則從數組2的副本中刪除該值的第一次出現,並將該值map到結果數組。

注意, t.index(v) t.slice!(t.index(v))用作短路保護,以防t.slice!(t.index(v))短路,以防在t t.slice!(t.index(v))中不存在該值。 我們還使用一個內聯技巧,將索引值分配給局部變量l(l = t.index v)因此我們可以在后續的布爾檢查中引用lt.slice!(l)

最后,由於只要array2內不存在array1值,此方法就會映射nil值,因此我們compact結果以刪除nil。


對於那些好奇的人,這里是到目前為止提出的解決方案的一些基准測試。 首先,這是在樣本陣列上執行100,000次操作的時鍾速度:

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)開始與眾不同。 Cary的解決方案也很好,尤其是在預處理方面:

                 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)

對於大小為1/10的數組,其大小為1000個整數,並且相交度較低 ,但是...

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

當我們循環10次時,flat_map解決方案會變平……除非我們使用預處理(Cary +):

                 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

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

這有點冗長,但是假設您的意思是值在相同位置:

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,因為所有三個數組的索引位置3都不相同:

array_1[3] = 2

array_2[3] = 3

array_3[3] = 3

我將嘗試以這種方式達到預期的結果:

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]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM