Скажем, я пытаюсь удалить элементы из массива a = [1,1,1,2,2,3]
. Если я выполняю следующее:
b = a - [1,3]
Затем я доберусь:
b = [2,2]
Однако я хочу, чтобы результат был
b = [1,1,2,2]
т.е. Я только удаляю один экземпляр каждого элемента в вычтенном векторе не все случаи. Существует ли простой путь в Ruby, чтобы сделать это?
Для скорости я сделал бы следующее, которое требует только одной передачи через каждый из двух массивов. Этот метод сохраняет порядок. Я сначала представлю код, который не видоизменяет исходный массив, затем показывает, как он может быть легко изменен для видоизменения.
arr = [1,1,1,2,2,3,1]
removals = [1,3,1]
h = removals.group_by(&:itself).transform_values(&:size)
#=> {1=>2, 3=>1}
arr.each_with_object([]) { |n,a|
h.key?(n) && h[n] > 0 ? (h[n] -= 1) : a << n }
#=> [1, 2, 2, 1]
arr
#=> [1, 1, 1, 2, 2, 3, 1]
Для видоизменения arr
запись:
h = removals.group_by(&:itself).transform_values(&:count)
arr.replace(arr.each_with_object([]) { |n,a|
h.key?(n) && h[n] > 0 ? (h[n] -= 1) : a << n })
#=> [1, 2, 2, 1]
arr
#=> [1, 2, 2, 1]
Это использует 21 <глоток> Св. глоток> метод века Hash#transform_values (новый в МРТ v2.4), но можно было вместо этого записать:
h = Hash[removals.group_by(&:itself).map { |k,v| [k,v.size] }]
или
h = removals.each_with_object(Hash.new(0)) { | n,h| h[n] += 1 }