我有一个类似于 [1,1,1,2,4,6,3,3] 的数组,我想要获取其中重复的元素列表,例如在这个例子中是 [1,3]。我写了以下代码:
my_array.select{|obj|my_array.count(obj)>1}.uniq
但它的效率非常低下(O(n²))。你有更好的想法吗?如果可能的话,简明扼要。
谢谢。
def repeated(array)
counts = Hash.new(0)
array.each{|val|counts[val]+=1}
counts.reject{|val,count|count==1}.keys
end
require 'set'
ary = [1,1,1,2,4,6,3,3]
dups = Set.new
test_set = Set.new
ary.each {|val| dups.add(val) unless test_set.add?(val)}
dups.to_a # [1, 3]
a = [1,1,1,2,4,6,3,3]
b = {}
a.each { |v| if b.has_key? v then b[v] = b[v]+1 else b[v]=1 end }
b.reject { |k,v| if v > 1 then false else true end }.keys
<< x
改为+ [x]
,将update
改为merge
以使其纯函数化):rs = xs.inject([[], {}]) do |(out, seen), x|
[(seen[x] == 1 ? (out << x) : out), seen.update(x => (seen[x] || 0)+1)]
end[0]
rs = xs.group_by { |x| x }.select { |y, ys| ys.size > 1 }.keys
rs = xs.group_by { |x| x }.map { |y, ys| y if ys.size > 1 }.compact
xs = [1,1,1]
。 - Janinject
[1,1,1,2,4,6,3,3].inject({}){ |ele, n| ele[n] = nil; ele }.keys
# => [1, 2, 4, 6, 3]
ele
哈希初始值为{}
,每次迭代都会向ele
哈希中添加一个键为数字n
和值为nil
的元素。在最后,ele
作为返回结果:
{1=>nil, 2=>nil, 4=>nil, 6=>nil, 3=>nil}
.keys
就可以完成任务。a = [1,1,1,2,4,6,3,3]
dupes = []
a.uniq.each do |u|
c = a.find_all {|e| e == u}.size
dupes << [u, c] unless c == 1
end
puts dupes.inspect
# dupes = [[1, 3], [3, 2]]
# 1 appears 3 times
# 3 appears twice
# to extract just the elment a bit cleaner
dupes = a.uniq.select do |u|
a.find_all {|e| e == u}.size != 1
end
puts dupes.inspect
# returns [1,3]
如果重复的条目总是连续的,就像您的示例一样,那么这将起作用;否则,您必须先进行排序。each_cons检查指定大小的滚动窗口。
require 'set'
my_array = [1,1,1,2,4,6,3,3]
dups = Set.new
my_array.each_cons(2) {|a,b| dups.add(a) if (a == b)}
p dups.to_a
1 对数组进行排序O(nlogn),然后遍历整个数组
2 创建一个集合,搜索当前数组元素是否在集合中存在,如果不存在,则插入并继续处理所有元素--再次O(nlogn)。
array.inject(Hash.new(0)) { |h, i| h[i] += 1; h }.reject { |v, c| c == 1 }.keys
。 - Marek Příhodadetect
,find_all
等问题。 - rapcalSet.new
。它在内部使用哈希表,在需要O(1)哈希键访问但又想要数组简单性的情况下非常好用。此外,它有助于可读性,因为所有逻辑都缩小到了明显易懂的dups.add(val) if seen_already.include?(val)
。 - Adamantish