web-dev-qa-db-fra.com

Supprimer des éléments du tableau Ruby

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?

58
Michael

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]

69
Norm212
[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
5
zetetic

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]
3
seph

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 }
0
Cary Swoveland
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
0
Lyres

Une solution simple que j'utilise fréquemment:

arr = ['remove me',3,4,2,45]

arr[1..-1]

=> [3,4,2,45]
0
The Whiz of Oz