Ruby array subtraction without removing items more than once

后端 未结 4 1048
余生分开走
余生分开走 2020-12-03 16:55

The canonical Array difference example in Ruby is:

[ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ]  #=>  [ 3, 3, 5 ]

What\'s the best way to ge

相关标签:
4条回答
  • 2020-12-03 17:34

    This is all I can think of so far:

    [1, 2, 4].each { |x| ary.delete_at ary.index(x) }
    
    0 讨论(0)
  • 2020-12-03 17:54
    class Array
      def subtract_once(b)
        h = b.inject({}) {|memo, v|
          memo[v] ||= 0; memo[v] += 1; memo
        }
        reject { |e| h.include?(e) && (h[e] -= 1) >= 0 }
      end
    end
    

    I believe this does what I want. Many thanks to @glebm

    0 讨论(0)
  • 2020-12-03 17:56

    Subtract values as many times as they appear in the other array, or any Enumerable:

    class Array
      # Subtract each passed value once:
      #   %w(1 2 3 1).subtract_once %w(1 1 2) # => ["3"]
      #   [ 1, 1, 2, 2, 3, 3, 4, 5 ].subtract_once([ 1, 2, 4 ]) => [1, 2, 3, 3, 5]
      # Time complexity of O(n + m)
      def subtract_once(values)
        counts = values.inject(Hash.new(0)) { |h, v| h[v] += 1; h }
        reject { |e| counts[e] -= 1 unless counts[e].zero? }
      end
    

    Subtract each unique value once:

    require 'set'
    class Array
      # Subtract each unique value once:
      #   %w(1 2 2).subtract_once_uniq %w(1 2 2) # => [2]
      # Time complexity of O((n + m) * log m)
      def subtract_once_uniq(values)
        # note that set is implemented 
        values_set = Set.new values.to_a 
        reject { |e| values_set.delete(e) if values_set.include?(e) }
      end
    end
    
    0 讨论(0)
  • 2020-12-03 17:59

    Similar to @Jeremy Ruten's answer but accounting for the fact that some elements may not be present:

    # remove each element of y from x exactly once
    def array_difference(x, y)
      ret = x.dup
      y.each do |element|
        if index = ret.index(element)
          ret.delete_at(index)
        end
      end
      ret
    end
    

    This answer also won't modify the original array as it operates, so:

    x = [1,2,3]
    y = [3,4,5]
    z = array_difference(x, y) # => [1,2]
    x == [1,2,3]               # => [1,2,3]
    
    0 讨论(0)
提交回复
热议问题