如何在Ruby中检测数组中的重复值?

9

假设我有一个类似以下结构的数组:

a = [cat, dog, cat, mouse, rat, dog, cat]

我该如何循环处理数组并对重复项执行某些操作,比如删除它们?
换句话说,如果我使用了 a.each do |i|,那么我该如何对 a[0]、a[1]、a[2]、a[3] 等进行比较,当找到需要的元素时(例如在本例中是 a[2]),将其推入堆栈或删除等操作?
我知道如何对键进行评估,但是怎样才能在同一数组中对值进行比较呢?
谢谢。
10个回答

12

你可以创建一个哈希表来存储每个元素重复出现的次数,从而只需要遍历一次数组。

h = Hash.new(0)
['a','b','b','c'].each{ |e| h[e] += 1 }

应该得到的结果是什么?

 {"a"=>1, "b"=>2, "c"=>1}

1
为什么不使用 h = Hash.new(0)h[e] += 1 呢? - Aleksander Pohl
语法问题,由程序员自行决定。 - ch4nd4n
这实际上是我想做的...但是...我无法弄清如何像这样使用nil?和增量方法。谢谢! - marcamillion
只是改进当前的答案。 - waldyr.ar

6
这个方法效率高而且相当简单:
require 'set'

visited = Set.new
array.each do |element|
  if visited.include?(element)
    # duplicated item
  else
    # first appearance
    visited << element
  end
end

4

试试这个:

class Array
    def find_dups
        uniq.map {|v| (self - [v]).size < (self.size - 1) ? v : nil}.compact
    end
end

a = ['cat', 'dog', 'cat', 'mouse', 'rat', 'dog', 'cat']

print a - a.find_dups # Removes duplicates

find_dups 将返回具有重复元素的元素


3
尝试这个:
array.inject({}){|h, e| h[e] = h[e].to_i + 1; h}
使用这段代码可以将数组转换为哈希表,并计算每个元素出现的次数。

array.inject(Hash.new(0)){|h, e| h[e] += 1; h}将数组中的元素注入到一个哈希表中,并统计每个元素出现的次数。 - Aleksander Pohl

2

使用a.uniq!来去除重复项。

另外,请查看ruby-doc.org,在那里您可以找到更多关于Ruby类方法的信息。


1
compact从数组中删除nil值。在这种情况下,它有什么帮助? - Sergio Tulentsev
1
你的解决方案可以去重,但它并不像 OP 所要求的那样寻找重复项。 - MMM

1
一个简单的解决方案是运行双重循环:
a.each_with_index do |a1, idx1|
  a.each_with_index do |a2, idx2|
    next if idx1 >= idx2 # Don't compare element to itself 
                         # and don't repeat comparisons already made

    # do something with a pair of elements (a1, a2)
  end
end

如果你只想消除重复项,这里有一个方法:Array#uniq


考虑过这个,但它看起来很凌乱。有更优雅、更符合 Ruby 风格的解决方案吗? - marcamillion
为了消除重复项,有一个方法。为了将所有元素彼此比较,有一个双重循环。我个人认为其中没有任何混乱。这是一个简单明了的代码,易于阅读。 - Sergio Tulentsev
Sergio,这种方法效率低下,因为你在进行不必要的比较,而这些比较在过去已经进行过了。你的第二个内部循环应该在每次循环时稍后开始迭代(即在数组中更靠后的位置)。 - MMM
@MMM 我并没有说它很高效,我只是说它很简单 :) - Sergio Tulentsev

1

最好的方法是将其与唯一版本进行比较。如果相同,则没有重复项,否则存在重复项。

unique_array = original_array.uniq

获取您的数组的唯一版本。
if original_array == unique_array then return true else return false

将其与您的原始数组进行比较。

简单!


1
这将打印数组中的所有重复项:

array.inject(Hash.new(0)) { |hash,val| 
  hash[val] += 1; 
  hash 
}.each_pair { |val,count| 
  puts "#{val} -> #{count}" if count > 1 
}

0
如果数组是可排序的,那么类似下面的代码将只返回重复项。
array.sort.each_cons(2).select {|p| p[0] == p[1] }.map &:first

对数组进行排序,然后将其映射到连续的元素对,选择相同的对,再将其映射到元素。


0

如果您只想摆脱重复项,最简单的方法是取出数组并执行array&array。使用&运算符。

如果您想知道这些重复项是什么,请将数组与array&array进行比较。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接