我有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 :(得分:12)
(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]
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_map与Enumerable#map的区别?假设我使用了map
而不是flat_map
。然后
a.map { |n| [n]*[array1.count(n), array2.count(n)].min }
#=> [[2, 2, 2], [3], [4], [8]]
flat_map
没有做任何更多的事情,在每个阵列的前面放置一个splat:
[*[2, 2, 2], *[3], *[4], *[8]]
#=> [2, 2, 2, 3, 4, 8]
如果数组array1
和array2
很大且效率问题,我们可以做一些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]
答案 1 :(得分:4)
这是一个有趣的; Cary的flat_map
解决方案特别聪明。这是使用常规旧版map
的替代单线版,并得到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提供一个Enumerator,它也可以让我们的方法链访问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
)。如果它存在,我们从array2的副本中移除值的第一次出现,并将值map
移除到我们的结果数组。
注意t.index(v)
之前的t.slice!(t.index(v))
检查用作短路保护,以防t
(我们的array2副本)中的值不存在。我们还使用在线技巧将索引值分配给局部变量l
:(l = t.index v)
所以我们可以在随后的布尔检查中引用l
:t.slice!(l)
。
最后,因为只要array2中不存在array1值,这种方法就会映射nil值,我们compact
会删除nils的结果。
对于那些好奇的人,这里是迄今为止提出的解决方案的一些基准测试。首先,以下是在样本阵列上执行操作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
答案 2 :(得分: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]
答案 3 :(得分: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]
答案 4 :(得分:0)
这有点冗长,但假设你指的是值在同一位置的位置:
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
答案 5 :(得分: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]