430 votes

Mapper et supprimer les valeurs nulles dans Ruby

J'ai une carte qui modifie ou définit une valeur nil. Je veux supprimer le néant, les entrées de la liste. La liste n'est pas besoin d'être conservés.

C'est ce que j'ai actuellement:

items.map! { |x| process_x url } # [1, 2, 3, 4, 5] => [1, nil, 3, nil, nil]
items.select! { |x| !x.nil? } # [1, nil, 3, nil, nil] => [1, 3]

Je suis conscient que je pourrais juste faire une boucle, et à condition de recueillir dans un autre tableau comme ceci:

new_items = []
items.each do |x|
    x = process_x x
    new_items.append(x) unless x.nil?
end
items = new_items

Mais il ne semble pas que ruby-esque. Est-il un bon moyen pour exécuter une fonction sur une liste retrait/exclusion de la nils que vous aller?

1094voto

the Tin Man Points 69148

Pourquoi ne pas utiliser compact?

[1, nil, 3, nil, nil].compact
=> [1, 3] 

Je tiens à rappeler aux gens que si vous obtenez un tableau contenant nils que la sortie d'un map bloc, et que le bloc essaie conditionnelle, les valeurs de retour, alors vous avez le code de l'odeur et de la nécessité de repenser votre logique.

Par exemple, si vous faites quelque chose qui fait ceci:

[1,2,3].map{ |i|
  if i % 2 == 0
    i
  end
}
# => [nil, 2, nil]

Alors ne le faites pas. Au lieu de cela, avant l' map, reject les trucs que vous ne voulez pas ou select de ce que tu veux:

[1,2,3].select{ |i| i % 2 == 0 }.map{ |i|
  i
}
# => [2]

Je considère l'aide d' compact pour nettoyer le gâchis comme un ultime effort pour se débarrasser de choses que nous n'avons pas gérer correctement, généralement parce que nous ne savions pas ce qui était à venir à nous. Nous devons toujours savoir de quel type de données est en train d'être jeté autour dans notre programme; Inattendu/inconnu de données est mauvais. Quand je vois nils dans un tableau sur lequel je travaille, je creuse dans pourquoi existent-elles, et voir si je peux améliorer le code de la génération de la matrice, plutôt que de permettre à Ruby de perdre du temps et de la mémoire de la génération nils puis tamisage à travers le tableau pour les supprimer plus tard.

'Just my $%0.2f.' % [2.to_f/100]

42voto

Evgenia Manolova Points 441

@the Tin Man, sympa - je ne connais pas cette méthode. Eh bien, certainement compact est le meilleur moyen, mais peut toujours être fait avec une simple soustraction:

 [1, nil, 3, nil, nil] - [nil]
 => [1, 3]
 

34voto

sawa Points 62592

Dans votre exemple

 items.map! { |x| process_x url } # [1, 2, 3, 4, 5] => [1, nil, 3, nil, nil]
 

il ne semble pas que les valeurs aient changé autrement que d'être remplacées par nil . Si tel est le cas, alors

 items.select{ |x| process_x url }
 

suffira.

31voto

Fred Willmore Points 180

Si vous vouliez un critère de rejet plus souple, par exemple, pour rejeter les chaînes vides aussi bien que zéro, vous pouvez utiliser:

 [1, nil, 3, 0, ''].reject(&:blank?)
 => [1, 3, 0] 
 

Si vous voulez aller plus loin et rejeter des valeurs nulles (ou appliquer une logique plus complexe au processus), vous pouvez passer un bloc à rejeter:

 [1, nil, 3, 0, ''].reject do |value| value.blank? || value==0 end
 => [1, 3]

[1, nil, 3, 0, '', 1000].reject do |value| value.blank? || value==0 || value>10 end
 => [1, 3]
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X