Project

General

Profile

Feature #11815

Updated by CaryInVictoria (Cary Swoveland) over 3 years ago

I propose that a method `Array#difference` be added to the Ruby core. It is similar to [Array#-](http://ruby-doc.org/core-2.2.0/Array.html#method-i-2D) but for each element of the (array) argument it removes remove only one matching element from the receiver. For example:

a = [1,2,3,4,3,2,2,4]
b = [2,3,4,4,4]

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

As you see, `a` contains three `2`'s and `b` `1`, so the first `3-1 #=> 2` `2`'s in `a` have been removed from `a` in constructing `c`. When `b` contains as least as many instances of an element as does `a`, `c` contains no instances of that element.

It could be implemented as follows:

class Array
def difference(other)
dup.tap do |cpy|
other.each do |e|
ndx = cpy.index(e)
cpy.delete_at(ndx) if ndx
end
end
end
end

Here are a few examples of its use:

*Identify an array's unique non-unique elements*

a = [1,3,2,4,3,4]
u = a.uniq #=> [1, 2, 3, 4]
u - a.difference(u) #=> [1, 2]

*Determine if two words of the same size are anagrams of each other*

w1, w2 = "stop", "pots"
w1.chars.difference(w2.chars).empty?
#=> true

*Identify a maximal number of 1-1 matches between the elements of two arrays and return an array of all elements from both arrays that were not matched*

a = [1, 2, 4, 2, 1, 7, 4, 2, 9]
b = [4, 7, 3, 2, 2, 7]
a.difference(b).concat(b.difference(a))
# => [1, 1, 4, 2, 9, 3, 7]

To remove elements from `a` starting at the end (rather the beginning) of `a`:

a = [1,2,3,4,3,2,2,4]
b = [2,3,4,4,4]

a.reverse.difference(b).reverse #=> [1,2,3,2]

`Array#difference!` could be defined in the obvious way.

Back