1

I'm trying to subtract an array from another array taking frequency into account, like this:

[1,2,2,2] some_code [1,2] # => [2,2]

What's the easiest way to accomplish this?

Using - removes all occurrences of the elements in the second array:

[1,2,2,2] - [1,2] # => []
sawa
  • 165,429
  • 45
  • 277
  • 381
kid_drew
  • 3,857
  • 6
  • 28
  • 38

4 Answers4

1
a1 = [1,2,2,2]
a2 = [1,2]    
a2.each { |e| (idx = a1.find_index e) && (a1.delete_at idx) }
#⇒ [2, 2]

Here we iterate the second array and delete elements from the first one, once per iteration, if those were found.

The first found element will be deleted.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
1
a = [1, 2, 2, 2]
b = [1, 2]

ha = a.each_with_object(Hash.new(0)){|e, h| h[e] += 1}
# => {1=>1, 2=>3}
hb = b.each_with_object(Hash.new(0)){|e, h| h[e] += 1}
# => {1=>1, 2=>1}
(ha.keys | hb.keys).flat_map{|k| Array.new([ha[k] - hb[k], 0].max, k)}
# => [2, 2]
sawa
  • 165,429
  • 45
  • 277
  • 381
0

If I understood the problem correctly, that you wish to delete single occurrence of each element of array b from array a, here is one way to do this:

a.keep_if {|i| !b.delete(i)}
#=> [2,2]

PS: Both arrays a and b are mutated by above code, so you may want to use dup to create a copy if you want to retain original arrays.

Wand Maker
  • 18,476
  • 8
  • 53
  • 87
  • 1
    If `a = [1,1]` and `b = [1,1]` I understand the OP wants an empty array returned (remove one `1` in `a` for each `1` in `b`), but `a.keep_if {|i| !b.delete(i)} #=> [1]` (because `delete(i)` deletes all instances of `i`). – Cary Swoveland Feb 26 '16 at 20:35
  • Thanks @cary ... will work on update. – Wand Maker Feb 27 '16 at 18:12
-2
def subtract arr_a, arr_b
  arr_b.each do |b| 
    idx = arr_a.index(b)
    arr_a.delete_at(idx) unless idx.nil?
  end
end

Output:

a = [1,2,2,2]
b = [1,2]
subtract a, b
puts "a: #{a}"
# => a: [2, 2]
Leo Brito
  • 2,053
  • 13
  • 20