2016-09-18 2 views
2

рубиновых документации:Аналог '&' с дубликатами

ичных & other_ary → new_ary

Set Intersection - Возвращает новый массив, содержащий элементы, общие для двух массивов, исключая любые дубликаты. Порядок сохраняется от исходного массива .

Но есть встроенный метод, чтобы сделать то же самое включая дублей?

Тестовый пример:

ary = [2, 7, 3, 7] 
other_ary = [7, 2, 7, 4] 
new_ary == [2, 7, 7] 
+0

Как бы то ни было, вы хотите исключить из массива не дубликаты. Это верно? – Makoto

+0

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

ответ

3

Раствор ниже, не самый элегантный один, но он возвращает правильный ответ в любом случае:

[ary, other_ary].map { |e| e.group_by { |e| e } } # &:itself since 2.3 
       .reduce { |memo, h| memo.merge(h) do |k, o, n| 
             [o.count, n.count].min 
            end } # merge to count 
       .select { |_, v| Integer === v } # select only merged 
       .flat_map { |k, v| [k] * v } # produce a result 

Или, более элегантный, мутирует массивы:

a1, a2 = [ary, other_ary].map(&:dup) # to keep originals intact 
loop.inject([]) do |memo| 
    break memo if a1.empty? 
    memo << (a2.delete_at(a2.index a1.pop) rescue nil) 
end.compact 
#⇒ [7, 7, 2] 

или даже:

a1, a2 = [ary, other_ary].map(&:dup) # to keep originals intact 
loop.each_with_object([]) do |_, memo| 
    break memo if a1.empty? 
    a2.index(a1.pop).tap { |i| memo << a2.delete_at(i) if i } 
end 
+0

Ваша первая строка несколько напоминает «You», Вероятно, я скажу «нет», но ты поедешь со мной на танец? ». –

+0

Приносим извинения. Предыдущий подход терпит неудачу с парами, такими как '[2, 0, 0, 0]', '[2, 2, 2, 3]', где число дубликатов в 'other_ary' выше, чем в' ary'. И ваш код обрабатывает его. – Viktor

2

Может быть что-то вроде этого?

ary.select{ |a| other_ary.include? a } 
#=> [2, 7, 7] 
+0

Каков ожидаемый результат, когда 'ary' включает в себя два' 7', но 'other_ary' только один? – spickermann

+0

, если ary включает в себя два '7', результат будет [7,7], если ary включает в себя один' 7', а другой включает оба, результат будет [7]. –

+0

Интересно, так ли Виктор ожидает, что этот метод будет работать? – spickermann

1

Мое понимание Проблема заключается в том, что вам даны два массива: a и b и хотите вернуть третью, которая содержит n копии каждого элемента e, присутствующие в обоих a и b, где n = [a.count(e), a.count(e)].max.

Пусть

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

Я предлагаю вам выполнить следующие три шага.

Построить подсчета хэш для каждого массива

ha = a.each_with_object(Hash.new(0)) { |n,h| h[n] += 1 } 
    #=> {3=>1, 1=>3, 2=>1, 0=>1} 
hb = b.each_with_object(Hash.new(0)) { |n,h| h[n] += 1 } 
    #=> {1=>1, 2=>2, 4=>2, 6=>1} 

Определить элементы, общие для обоих массивов

common_elements = a & b 
    #=> [1, 2] 

Построить желаемый массив

common_elements.flat_map { |n| [n]*[ha[n], hb[n]].max } 
    #=> [1, 1, 1, 2, 2] 
Смежные вопросы