Comment faire pour supprimer tous les éléments vides (éléments de liste vides) d'un fichier Hash ou YAML imbriqué ?
C'est bien fait, mais cela vaut la peine de noter que, contrairement à la réponse acceptée, l'extension Rails n'est pas récursive ?
Comment faire pour supprimer tous les éléments vides (éléments de liste vides) d'un fichier Hash ou YAML imbriqué ?
Ajout de Rails 4.1 Hash#compact y Hash#compact ! en tant qu'extension de base de l'extension de Ruby Hash
classe. Vous pouvez les utiliser comme ceci :
hash = { a: true, b: false, c: nil }
hash.compact
# => { a: true, b: false }
hash
# => { a: true, b: false, c: nil }
hash.compact!
# => { a: true, b: false }
hash
# => { a: true, b: false }
{ c: nil }.compact
# => {}
Attention : cette implémentation n'est pas récursive. Par curiosité, ils l'ont implémentée en utilisant #select
au lieu de #delete_if
pour des raisons de performance. Voir ici pour le benchmark .
Au cas où vous souhaiteriez l'intégrer à votre application Rails 3 :
# config/initializers/rails4_backports.rb
class Hash
# as implemented in Rails 4
# File activesupport/lib/active_support/core_ext/hash/compact.rb, line 8
def compact
self.select { |_, value| !value.nil? }
end
end
Utilisez hsh.delete_if . Dans votre cas spécifique, quelque chose comme : hsh.delete_if { |k, v| v.empty? }
Récursif : proc = Proc.new { |k, v| v.kind_of?(Hash) ? (v.delete_if(&l); nil) : v.empty? }; hsh.delete_if(&proc)
Je crois qu'il y a une faute de frappe dans votre réponse, par ailleurs correcte : proc = Proc.new { |k, v| v.kind_of ?(Hash) ? (v.delete_if(&proc) ; nil) : v.empty ? } ; hsh.delete_if(&proc)
Vous pourriez ajouter une méthode compacte à Hash comme ceci
class Hash
def compact
delete_if { |k, v| v.nil? }
end
end
ou pour une version qui supporte la récursion
class Hash
def compact(opts={})
inject({}) do |new_hash, (k,v)|
if !v.nil?
new_hash[k] = opts[:recurse] && v.class == Hash ? v.compact(opts) : v
end
new_hash
end
end
end
Il y a un problème : Hash#delete_if
est une opération destructive, tandis que compact
Les méthodes ne modifient pas l'objet. Vous pouvez utiliser Hash#reject
. Ou appelez la méthode Hash#compact!
.
Veuillez noter que compact
y compact!
sont standard dans Ruby => 2.4.0, et Rails => 4.1. Ils sont cependant non récursifs.
Je sais que ce fil est un peu vieux mais j'ai trouvé une meilleure solution qui supporte les hachages multidimensionnels. Il utilise delete_if ? sauf qu'il est multidimensionnel et nettoie tout ce qui a une valeur vide par défaut et si un bloc est passé, il est transmis vers le bas à travers ses enfants.
# Hash cleaner
class Hash
def clean!
self.delete_if do |key, val|
if block_given?
yield(key,val)
else
# Prepeare the tests
test1 = val.nil?
test2 = val === 0
test3 = val === false
test4 = val.empty? if val.respond_to?('empty?')
test5 = val.strip.empty? if val.is_a?(String) && val.respond_to?('empty?')
# Were any of the tests true
test1 || test2 || test3 || test4 || test5
end
end
self.each do |key, val|
if self[key].is_a?(Hash) && self[key].respond_to?('clean!')
if block_given?
self[key] = self[key].clean!(&Proc.new)
else
self[key] = self[key].clean!
end
end
end
return self
end
end
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.