Ruby - 数组交集(带有重复项)

Вла*_*рко 7 ruby arrays intersection

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

array1 & array2返回[2,3,4,8],但我需要保留重复.

Car*_*and 13

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

步骤:

a = array1 & array2 
  #=> [2, 3, 4, 8]  
Run Code Online (Sandbox Code Playgroud)

a(2)的第一个元素被传递给块并分配给块变量:

n = 2
Run Code Online (Sandbox Code Playgroud)

并执行块计算:

[2]*[array1.count(2), array2.count(2)].min
  #=> [2]*[4,3].min
  #=> [2]*3
  #=> [2,2,2]
Run Code Online (Sandbox Code Playgroud)

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

flat_map 没有做任何更多的事情,在每个阵列的前面放置一个splat:

[*[2, 2, 2], *[3], *[4], *[8]]
  #=> [2, 2, 2, 3, 4, 8] 
Run Code Online (Sandbox Code Playgroud)

如果阵列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]
Run Code Online (Sandbox Code Playgroud)

  • 到目前为止最好的答案(在不太大的阵列上,因为我的是O(N),在最坏的情况下这个是O(N²).) (2认同)