Issue #11815 has been updated by marcandre (Marc-Andre Lafortune).


Note that `Enumerable#tally` make many of these tasks based on the number of appearances reasonably easy to do. In the examples of the original poster:

Determine if two arrays of the same size contain the same elements

```ruby
  a = [2,1,4,2,5,3,3,1]
  b = [3,4,1,1,2,3,5,2] 
  a.difference(b).empty?
    #=> true

  # Use tally:
  a.tally == b.tally
    # => true
  # assuming they can't be sorted, otherwise using sort works too:
  a.sort == b.sort
```

Identify an array's unique elements

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

  # Use tally:
  a.tally.select {|k, nb| nb == 1}.keys # => [1, 2]
  # Makes it easy to select elements on a diffent criteria, e.g. == 2 for exactly duplicated, etc.
```

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] 

  a.tally.merge(b.tally) { |_, nb_a, nb_b| nb_a - nb_b }.flat_map { |obj, n| [obj] * n.abs }
```



----------------------------------------
Feature #11815: Proposal for method `Array#difference`
https://bugs.ruby-lang.org/issues/11815#change-86626

* Author: CaryInVictoria (Cary Swoveland)
* Status: Open
* Priority: Normal
----------------------------------------
I propose that a method `Array#difference` be added to the Ruby core. *(`Array#difference`, which appears to be an alias of `Array#-`, was added to Ruby 2.6. Accordingly, I would propose that this method be named `remove`, but I will not make any changes here.)*  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 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` contains `1`, so the first `2` in `a` has 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)
        h = other.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
        reject { |e| h[e] > 0 && h[e] -= 1 }
      end
    end

Here are a few examples of its use:

*Determine if two arrays of the same size contain the same elements*

      a = [2,1,4,2,5,3,3,1]
      b = [3,4,1,1,2,3,5,2] 
      a.difference(b).empty?
        #=> true

*Identify an array's unique elements*

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

*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.

More information is in my answer to [this SO question](http://stackoverflow.com/questions/24987054/how-to-select-unique-elements).




-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>