Сравнение элементов массива, включая дубликаты

Я пытаюсь проверить, содержит ли массив каждый элемент другого массива. Кроме того, я хочу учитывать дубликаты. Например:

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

содержит [1, 2, 3, 3], но не содержит [2, 2, "abc" ] - слишком много 2

Я пробовал нижеследующее, но, очевидно, не учитываю обманы.

other_arrays.each { |i| array.include? i }

Ответ 1

Этот метод повторяется один раз по обеим массивам. Для каждого массива он создает хэш с количеством вхождений каждого элемента.

Затем он проверяет, что для каждого уникального элемента в subset в 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

Если вы не хотите исправлять класс Array, вы можете определить:

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

Ответ 2

Сначала вы можете создать полезный метод экземпляра для класса 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

Затем все элементы массива a содержатся в массиве b, если следующий метод возвращает true.

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

Например,

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

Я нашел, что Array#difference имеет такое широкое приложение, что я предложил, чтобы он был добавлен в ядро ​​Ruby. Подробности о методе и его использовании можно найти по ссылке, а также в ответе на этот вопрос SO.