Ruby difference in array including duplicates

后端 未结 3 959
你的背包
你的背包 2020-12-10 19:55

[1,2,3,3] - [1,2,3] produces the empty array []. Is it possible to retain duplicates so it returns [3]?

相关标签:
3条回答
  • 2020-12-10 20:20

    As far as I know, you can't do this with a built-in operation. Can't see anything in the ruby docs either. Simplest way to do this would be to extend the array class like this:

    class Array
        def difference(array2)
            final_array = []
            self.each do |item|
                if array2.include?(item)
                    array2.delete_at(array2.find_index(item))
                else
                    final_array << item
                end
            end
        end
    end
    

    For all I know there's a more efficient way to do this, also

    0 讨论(0)
  • 2020-12-10 20:24

    EDIT: As suggested by user2864740 in question comments, using Array#slice! is a much more elegant solution

    def arr_sub(a,b)
        a = a.dup #if you want to preserve the original array
        b.each {|del| a.slice!(a.index(del)) if a.include?(del) }
        return a
    end
    

    Credit:

    My original answer

    def arr_sub(a,b)
        b = b.each_with_object(Hash.new(0)){ |v,h| h[v] += 1 }
    
        a = a.each_with_object([]) do |v, arr| 
            arr << v if b[v] < 1
            b[v] -= 1
        end
    end
    
    arr_sub([1,2,3,3],[1,2,3]) # a => [3]
    arr_sub([1,2,3,3,4,4,4],[1,2,3,4,4]) # => [3, 4]
    arr_sub([4,4,4,5,5,5,5],[4,4,5,5,5,5,6,6]) # => [4]
    
    0 讨论(0)
  • 2020-12-10 20:31

    I am so glad you asked. I would like to see such a method added to the class Array in some future version of Ruby, as I have found many uses for it:

    class Array
      def difference(other)
        h = other.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
        reject { |e| h[e] > 0 && h[e] -= 1 }
      end
    end
    

    A description of the method and links to some of its applications are given here.

    By way of example:

    a = [1,2,3,4,3,2,4,2]
    b = [2,3,4,4,4]
    
    a - b          #=> [1]
    a.difference b #=> [1,2,3,2]
    

    Ruby v2.7 gave us the method Enumerable#tally, allowing us to replace the first line of the method with

    h = other.tally
    
    0 讨论(0)
提交回复
热议问题