Ruby 从重复的数组元素中删除

Ruby 从重复的数组元素中删除,ruby,arrays,Ruby,Arrays,从重复的数组元素中删除的最佳方法是什么。 例如,从数组 a = [4, 3, 3, 1, 6, 6] 需要 a = [4, 1] 我的方法对大量元素的处理速度太慢 arr = [4, 3, 3, 1, 6, 6] puts arr.join(" ") nouniq = [] l = arr.length uniq = nil for i in 0..(l-1) for j in 0..(l-1) if (arr[j] == arr[i]) and ( i != j )

从重复的数组元素中删除的最佳方法是什么。 例如,从数组

a = [4, 3, 3, 1, 6, 6]
需要

a = [4, 1]
我的方法对大量元素的处理速度太慢

arr = [4, 3, 3, 1, 6, 6]
puts arr.join(" ")
nouniq = []
l = arr.length
uniq = nil
for i in 0..(l-1)
  for j in 0..(l-1) 
    if (arr[j] == arr[i]) and ( i != j )
      nouniq << arr[j]
    end
  end
end
arr = (arr - nouniq).compact

puts arr.join(" ")
arr=[4,3,3,1,6,6]
放置arr.join(“”)
名词IQ=[]
l=arr.length
uniq=nil
对于0中的i…(l-1)
对于0中的j..(l-1)
如果(arr[j]==arr[i])和(i!=j)
名词
更复杂但更快的解决方案(
O(n)
我相信:)

a=[4,3,3,1,6,6]
ar=[]

add=proc{| to,form | to,无需引入原始数组的单独副本并使用inject:

[4, 3, 3, 1, 6, 6].inject({}) {|s,v| s[v] ? s.merge({v=>s[v]+1}) : s.merge({v=>1})}.select {|k,v| k if v==1}.keys
 => [4, 1] 

下面是我对Perl程序员使用的一个解决方案的看法,该解决方案使用散列来累积数组中每个元素的计数:

ary = [4, 3, 3, 1, 6, 6]

ary.inject({}) { |h,a| 
  h[a] ||= 0
  h[a] += 1
  h 
}.select{ |k,v| v == 1 }.keys # => [4, 1]
如果这很重要的话,它可以在一行上,在
地图的行之间明智地使用分号

另一种方式是:

ary.inject({}) { |h,a| h[a] ||= 0; h[a] += 1; h }.map{ |k,v| k if (v==1) }.compact # => [4, 1]

它将
select{…}.keys
替换为
map{…}.compact
,因此这并不是一个真正的改进,对我来说更难理解。

我需要类似的东西,所以测试了几种不同的方法。这些方法都返回一个在原始数组中重复的项目数组:

module Enumerable
def dups
  inject({}) {|h,v| h[v]=h[v].to_i+1; h}.reject{|k,v| v==1}.keys
end
def only_duplicates
  duplicates = []
  self.each {|each| duplicates << each if self.count(each) > 1}
  duplicates.uniq
end
def dups_ej
  inject(Hash.new(0)) {|h,v| h[v] += 1; h}.reject{|k,v| v==1}.keys
end
def dedup
  duplicates = self.dup
  self.uniq.each { |v| duplicates[self.index(v)] = nil }
  duplicates.compact.uniq
end
end
因此,在这些方法中,Enumerable.dedup算法似乎是最好的:

  • 复制原始数组,使其不可变
  • 获取uniq数组元素
  • 对于每个唯一元素:nil dup数组中的第一个出现
  • 压缩结果

如果(array-array.uniq)工作正常就好了!(它不会-它会删除所有内容)

@Joe:我仍在试图找到一种更好的方法。肯定有一种方法可以使用
inject
,因为你可以简单地证明,你可以用
每个
做的所有事情都可以用
inject
来完成,
Enumerable
中的所有方法都是基于
每个
来完成的。因此,你可以用任何co>来做任何事情
Enumerable
方法的组合也可以通过
inject
来完成。这是否更具可读性是另一回事。我想把它降低到O(n)的摊销最坏情况步骤复杂性,因为@fl00r已经提供了一个更好的O(n²)解决方案。@Jörg你能给出一些关于O(n)和O(n²)的链接吗Ruby:)@Jörg查看我的提交inject@fl00r:该符号称为Bachmann-Landau符号。我在这里使用的特定上下文称为算法复杂性理论。在StackOverflow上,这两个主题都有很多问题,尽管你最好的选择可能是算法和数据结构教科书或像这样的课程。C实现的
count\u by
方法比ruby实现的
count\u by.map
在YARV中更快(尽管仍然是相同的“大O”)吗?这是可行的,但请注意这是
O(n^2)
,即对于大型数组来说效率非常低(与OP算法的顺序相同)。请参见Jörg的答案以获得有效的答案,但对于小型数组,它将更快[4,3,3,1,6,6]。注入({}){s,v{s.merge(s[v]?{v=>s[v]+1}:{v=>1})。如果v==1},则选择{k,v{k。键
ary = [4, 3, 3, 1, 6, 6]

ary.inject({}) { |h,a| 
  h[a] ||= 0
  h[a] += 1
  h 
}.select{ |k,v| v == 1 }.keys # => [4, 1]
ary.inject({}) { |h,a| h[a] ||= 0; h[a] += 1; h }.map{ |k,v| k if (v==1) }.compact # => [4, 1]
module Enumerable
def dups
  inject({}) {|h,v| h[v]=h[v].to_i+1; h}.reject{|k,v| v==1}.keys
end
def only_duplicates
  duplicates = []
  self.each {|each| duplicates << each if self.count(each) > 1}
  duplicates.uniq
end
def dups_ej
  inject(Hash.new(0)) {|h,v| h[v] += 1; h}.reject{|k,v| v==1}.keys
end
def dedup
  duplicates = self.dup
  self.uniq.each { |v| duplicates[self.index(v)] = nil }
  duplicates.compact.uniq
end
end
test_benchmark_integer
                                    user     system      total        real
Enumerable.dups                 2.560000   0.040000   2.600000 (  2.596083)
Enumerable.only_duplicates      6.840000   0.020000   6.860000 (  6.879830)
Enumerable.dups_ej              2.300000   0.030000   2.330000 (  2.329113)
Enumerable.dedup                1.700000   0.020000   1.720000 (  1.724220)
test_benchmark_strings
                                    user     system      total        real
Enumerable.dups                 4.650000   0.030000   4.680000 (  4.722301)
Enumerable.only_duplicates     47.060000   0.150000  47.210000 ( 47.478509)
Enumerable.dups_ej              4.060000   0.030000   4.090000 (  4.123402)
Enumerable.dedup                3.290000   0.040000   3.330000 (  3.334401)
..
Finished in 73.190988 seconds.