Disons que j'essaie de supprimer des éléments du tableau a = [1,1,1,2,2,3]
. Si j'effectue les tâches suivantes:
b = a - [1,3]
Ensuite, j'aurai:
b = [2,2]
Cependant, je veux que le résultat soit
b = [1,1,2,2]
c'est-à-dire que je ne supprime qu'une instance de chaque élément du vecteur soustrait, pas tous les cas. Ruby existe-t-il un moyen simple de faire cela?
Vous pouvez faire:
a= [1,1,1,2,2,3]
delete_list = [1,3]
delete_list.each do |del|
a.delete_at(a.index(del))
end
résultat: [1, 1, 2, 2]
[1,3].inject([1,1,1,2,2,3]) do |memo,element|
memo.tap do |memo|
i = memo.find_index(e)
memo.delete_at(i) if i
end
end
Pas très simple mais:
a = [1,1,1,2,2,3]
b = a.group_by {|n| n}.each {|k,v| v.pop [1,3].count(k)}.values.flatten
=> [1, 1, 2, 2]
Gère également le cas des multiples dans le 'subtrahend':
a = [1,1,1,2,2,3]
b = a.group_by {|n| n}.each {|k,v| v.pop [1,1,3].count(k)}.values.flatten
=> [1, 2, 2]
EDIT: il s’agit plus d’une amélioration combinant Norm212 et ma réponse pour créer une solution "fonctionnelle".
b = [1,1,3].each.with_object( a ) { |del| a.delete_at( a.index( del ) ) }
Mettez-le dans un lambda si nécessaire:
subtract = lambda do |minuend, subtrahend|
subtrahend.each.with_object( minuend ) { |del| minuend.delete_at( minuend.index( del ) ) }
end
puis:
subtract.call a, [1,1,3]
Pour la vitesse, je voudrais faire ce qui suit, qui nécessite seulement un passage à travers chacun des deux tableaux. Cette méthode préserve l'ordre. Je vais d'abord présenter un code qui ne mute pas le tableau d'origine, puis montrer comment il peut être facilement modifié pour muter.
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]
Pour muter arr
, écrivez:
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]
Cela utilise le 21st century method Hash # transform_values (nouveau dans MRI v2.4), mais on pourrait plutôt écrire:
h = Hash[removals.group_by(&:itself).map { |k,v| [k,v.size] }]
ou
h = removals.each_with_object(Hash.new(0)) { | n,h| h[n] += 1 }
a = [1,1,1,2,2,3]
a.slice!(0) # remove first index
a.slice!(-1) # remove last index
# a = [1,1,2,2] as desired
Une solution simple que j'utilise fréquemment:
arr = ['remove me',3,4,2,45]
arr[1..-1]
=> [3,4,2,45]