Подсчет совпадающих элементов в массиве
Учитывая два массива одинакового размера, как я могу найти количество совпадающих элементов без учета позиции?
Например:
-
[0,0,5]
и [0,5,5]
возвращают совпадение 2
, так как существует один 0
и один 5
,
-
[1,0,0,3]
и [0,0,1,4]
вернет совпадение 3
, так как есть два совпадения 0
и одно совпадение 1
;
-
[1,2,2,3]
и [1,2,3,4]
вернет совпадение 3
.
Я попробовал несколько идей, но все они, как правило, довольно грубые и запутанные. Я предполагаю, что есть какая-то приятная рубиновая идиома или, может быть, регулярное выражение, которое было бы элегантным ответом на это решение.
Ответы
Ответ 1
Вы можете выполнить это с помощью count
:
a.count{|e| index = b.index(e) and b.delete_at index }
Демонстрация
или inject
:
a.inject(0){|count, e| count + ((index = b.index(e) and b.delete_at index) ? 1 : 0)}
Демонстрация
или select
и length
(или это псевдоним - size
):
a.select{|e| (index = b.index(e) and b.delete_at index)}.size
Демонстрация
Результаты:
-
a, b = [0,0,5], [0,5,5]
вывод: => 2
;
-
a, b = [1,2,2,3], [1,2,3,4]
вывод: => 3
;
-
a, b = [1,0,0,3], [0,0,1,4]
вывод => 3
.
Ответ 2
(arr1 & arr2).map { |i| [arr1.count(i), arr2.count(i)].min }.inject(0, &:+)
Здесь (arr1 & arr2)
возвращает список значений uniq, которые содержат оба массива, arr.count(i)
подсчитывает количество элементов i
в массиве.
Ответ 3
Другое использование для могущественного (и очень необходимого) Array#difference
, который я определил в своем ответе здесь. Этот метод похож на Array#-
. Различие между этими двумя способами проиллюстрировано в следующем примере:
a = [1,2,3,4,3,2,4,2]
b = [2,3,4,4,4]
a - b #=> [1]
a.difference b #=> [1, 3, 2, 2]
Для настоящей заявки:
def number_matches(a,b)
left_in_b = b
a.reduce(0) do |t,e|
if left_in_b.include?(e)
left_in_b = left_in_b.difference [e]
t+1
else
t
end
end
end
number_matches [0,0,5], [0,5,5] #=> 2
number_matches [1,0,0,3], [0,0,1,4] #=> 3
number_matches [1,0,0,3], [0,0,1,4] #=> 3
Ответ 4
Используя multiset gem:
(Multiset.new(a) & Multiset.new(b)).size
Multiset похож на Set, но позволяет дублировать значения. &
- это оператор "set intersection" (возвращает все вещи, находящиеся в обоих наборах).
Ответ 5
Я не думаю, что это идеальный ответ, потому что он немного сложный, но...
def count(arr)
arr.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
end
def matches(a1, a2)
m = 0
a1_counts = count(a1)
a2_counts = count(a2)
a1_counts.each do |e, c|
m += [a1_counts, a2_counts].min
end
m
end
В принципе, сначала напишите метод, который создает хэш из массива числа раз, когда каждый элемент появляется. Затем используйте их, чтобы суммировать наименьшее количество раз, когда каждый элемент появляется в обоих массивах.