【问题标题】:How can I efficiently extract repeated elements in a Ruby array? [duplicate]如何有效地提取 Ruby 数组中的重复元素? [复制]
【发布时间】:2010-10-21 16:11:31
【问题描述】:

我有一个类似 [1,1,1,2,4,6,3,3] 的数组,我想获取重复元素的列表,在本例中为 [1,3]。我是这样写的:

my_array.select{|obj|my_array.count(obj)>1}.uniq

但可悲的是效率低下 (o(n²))。你有更好的主意吗?尽可能简洁。

谢谢

【问题讨论】:

    标签: ruby arrays count elements


    【解决方案1】:

    使用inject

    [1,1,1,2,4,6,3,3].inject({}){ |ele, n| ele[n] = nil; ele }.keys 
    # => [1, 2, 4, 6, 3] 
    

    解释:

    ele 哈希它被初始化为{},每次迭代都会将一个带有数字nnil 值的键添加到ele 哈希中。最后ele 返回为:

    {1=>nil, 2=>nil, 4=>nil, 6=>nil, 3=>nil}
    

    我们只想要钥匙,所以.keys 结束工作。

    【讨论】:

    • 谢谢,但我只想要 repeated 元素,如示例中所示。
    【解决方案2】:

    一个 O(n) 解决方案(将 << 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]
    • @Jan,确实,感谢您的指出。查看更新。
    • group_by 不是更合适吗?
    • @Andrew。我认为已经有一个使用 group_by 的解决方案,但似乎它在另一个问题中。我会添加它。现在 Ruby 已经对哈希进行了排序,我们可以保留原始枚举的顺序。但是,它的空间效率低于自定义解决方案。
    【解决方案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
    

    【讨论】:

      【解决方案4】:

      我正在考虑计算一个唯一元素在数组中出现的次数。 就像最初的建议一样,它可能真的效率低下,但看这个问题很有趣。 我没有对更大的数组进行任何基准测试,所以这只是一个练习。

      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]
      

      【讨论】:

        【解决方案5】:

        灵感来自 Ilya Haykinson 的回答:

        def repeated(array)
          counts = Hash.new(0)
          array.each{|val|counts[val]+=1}
          counts.reject{|val,count|count==1}.keys
        end
        

        【讨论】:

        • 是的,我认为这比我的更干净。只是为了好玩,假设 Ruby >= 1.8.7 中的“tap”方法可用,这里的方法全部放在一行上。 array.inject(Hash.new(0)){|counts,val|counts.tap{|c|c[val]+=1}}.reject{|val,count|count==1}.keys 我认为不过,您的更具可读性。 :)
        • 我真的非常喜欢这个解决方案,我喜欢它,因为它是所有 O(n) 解决方案中可读性/可理解性最高的一个。这是一个单行修改,只是为了好玩:array.inject(Hash.new(0)) { |h, i| h[i] += 1; h }.reject { |v, c| c == 1 }.keys
        • 谢谢!太棒了...我正在遭受detectfind_all 等的折磨
        • 这没关系,但任何认为这是最佳答案的人都需要熟悉Set.new。它在引擎盖下使用哈希,当您需要 O(1) 哈希键访问但具有数组的简单性时,它非常有用。此外,它还有助于提高可读性,因为所有逻辑都缩小到非常明显的 dups.add(val) if seen_already.include?(val)
        【解决方案6】:

        这样的事情怎么样?它将在 O(n) 中运行。

        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
        

        【讨论】:

        • 我喜欢这个主意。你可以像这样美化最后一行: b.reject{|k,v| v==1}.keys
        • 另外,你可以使用 b=Hash.new(0),然后你会有一个更简单的第三行:a.each{|v|b[v]+=1}
        【解决方案7】:

        使用 Ruby 的 Set 库:

        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]
        

        我相信这应该是 O(n),因为 Set#add 和 Set#add?据我所知,是常数时间操作。

        【讨论】:

          【解决方案8】:

          一些想法:您必须找出正确的库数据结构:

          1对数组O(nlogn)排序,然后遍历数组

          2 创建一个集合,在集合中搜索当前数组元素,如果没有找到,插入并继续查找所有元素——再次O(nlogn)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-10-29
            • 1970-01-01
            • 2010-10-08
            • 2014-05-16
            • 2019-10-21
            • 1970-01-01
            • 2019-11-11
            • 2023-01-28
            相关资源
            最近更新 更多