2

I am trying to see if an array contains each element of another array. Plus I want to account for the duplicates. For example:

array = [1, 2, 3, 3, "abc", "de", "f"]

array contains [1, 2, 3, 3] but does not contain [2, 2, "abc"] - too many 2's

I have tried the below but obviously doesn't take into account the dupes.

other_arrays.each { |i| array.include? i }
kouty
  • 320
  • 8
  • 17

2 Answers2

3

This method iterates once over both arrays. For each array, it creates a hash with the number of occurences of each element.

It then checks that for every unique element in subset, there are at least as many elements in superset.

class Array
  def count_by
    each_with_object(Hash.new(0)) { |e, h| h[e] += 1 }
  end

  def subset_of?(superset)
    superset_counts = superset.count_by
    count_by.all? { |k, count| superset_counts[k] >= count }
  end
end

[1, 2, 3, 3, "abc", "de", "f"].count_by
#=> {1=>1, 2=>1, 3=>2, "abc"=>1, "de"=>1, "f"=>1}

[1, 2, 3, 3].count_by
#=> {1=>1, 2=>1, 3=>2}

[1, 2, 3, 3].subset_of? [1, 2, 3, 3, "abc", "de", "f"]
#=> true
[2, 2, "abc"].subset_of? [1, 2, 3, 3, "abc", "de", "f"]
#=> false

If you don't want to patch the Array class, you could define :

count_by(array) and subset_of?(array1, array2).

Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
0

You could first create a useful instance method for the class Array:

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

Then all elements of an array a are contained in array b if the following method returns true.

def subarray?(a,b)
  a.difference(b).empty?
end

For example,

subarray? [1,2,3], [1,4,"cat",3,2]
  #=> true
subarray? [1,2,3], [1,4,"cat",3,5]
  #=> false

I've found Array#difference has such wide application that I proposed that it be added to the Ruby core. Details about the method and its uses can be found at the link and also in my answer to this SO question.

Community
  • 1
  • 1
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100