Enlever tous les éléments vides d’un hash / YAML?

Comment pourrais-je procéder pour supprimer tous les éléments vides (éléments de liste vides) d’un fichier Hash ou YAML nested?

Vous pouvez append une méthode compacte à Hash comme ceci

class Hash def compact delete_if { |k, v| v.nil? } end end 

ou pour une version prenant en charge la récursivité

 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 

Utilisez hsh.delete_if . Dans votre cas spécifique, quelque chose comme: hsh.delete_if { |k, v| v.empty? } hsh.delete_if { |k, v| v.empty? }

Rails 4.1 a ajouté Hash # compact et Hash # compact! comme une extension de base de la classe Ruby’s Hash . 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 # => {} 

Heads up: cette mise en œuvre n’est pas récursive. À titre de curiosité, ils l’ont implémenté en utilisant #select au lieu de #delete_if pour des raisons de performances. Voir ici pour le benchmark .

Dans le cas où vous souhaitez le transférer vers 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 

Celui-ci supprime également les hachages vides:

 swoop = Proc.new { |k, v| v.delete_if(&swoop) if v.kind_of?(Hash); v.empty? } hsh.delete_if &swoop 

Je sais que ce sujet est un peu ancien mais je suis arrivé avec une meilleure solution qui prend en charge les hachages multidimensionnels. Il utilise delete_if? sauf son multidimensionnel et nettoie tout ce qui a une valeur vide par défaut et si un bloc est passé, il est transmis par 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.ssortingp.empty? if val.is_a?(Ssortingng) && 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 

J’ai créé une méthode deep_compact pour filtrer de manière récursive les enregistrements nuls (et éventuellement aussi les enregistrements vierges):

 class Hash # Recursively filters out nil (or blank - eg "" if exclude_blank: true is passed as an option) records from a Hash def deep_compact(options = {}) inject({}) do |new_hash, (k,v)| result = options[:exclude_blank] ? v.blank? : v.nil? if !result new_value = v.is_a?(Hash) ? v.deep_compact(options).presence : v new_hash[k] = new_value if new_value end new_hash end end end 

Vous pouvez utiliser Hash # reject pour supprimer les paires clé / valeur vides d’un hash ruby.

 # Remove empty ssortingngs { a: 'first', b: '', c: 'third' }.reject { |key,value| value.empty? } #=> {:a=>"first", :c=>"third"} # Remove nil {a: 'first', b: nil, c: 'third'}.reject { |k,v| v.nil? } # => {:a=>"first", :c=>"third"} # Remove nil & empty ssortingngs {a: '', b: nil, c: 'third'}.reject { |k,v| v.nil? || v.empty? } # => {:c=>"third"} 

Ruby Hash#compact , Hash#compact! et Hash#delete_if! ne travaille pas sur le nid nested, empty? et / ou blank? valeurs. Notez que les deux dernières méthodes sont destructives et que toutes les valeurs nil , "" , false , [] et {} sont considérées comme blank? .

Hash#compact et Hash#compact! sont uniquement disponibles dans Rails, ou Ruby version 2.4.0 et supérieure.

Voici une solution non destructive qui supprime tous les tableaux vides, les hachages, les chaînes et les valeurs nil , tout en conservant toutes les valeurs false :

( blank? peut être remplacé par nil? ou empty? selon les besoins.)

 def remove_blank_values(hash) hash.each_with_object({}) do |(k, v), new_hash| unless v.blank? && v != false v.is_a?(Hash) ? new_hash[k] = remove_blank_values(v) : new_hash[k] = v end end end 

Une version destructive:

 def remove_blank_values!(hash) hash.each do |k, v| if v.blank? && v != false hash.delete(k) elsif v.is_a?(Hash) hash[k] = remove_blank_values!(v) end end end 

Ou, si vous souhaitez append les deux versions en tant que méthodes d’instance dans la classe Hash :

 class Hash def remove_blank_values self.each_with_object({}) do |(k, v), new_hash| unless v.blank? && v != false v.is_a?(Hash) ? new_hash[k] = v.remove_blank_values : new_hash[k] = v end end end def remove_blank_values! self.each_pair do |k, v| if v.blank? && v != false self.delete(k) elsif v.is_a?(Hash) v.remove_blank_values! end end end end 

Autres options:

  • Remplacez v.blank? && v != false v.blank? && v != false avec v.nil? || v == "" v.nil? || v == "" v.nil? || v == "" pour supprimer ssortingctement les chaînes vides et les valeurs nil
  • Remplacez v.blank? && v != false v.blank? && v != false avec v.nil? supprimer ssortingctement les valeurs nil
  • Etc.

EDITED 2017/03/15 pour garder les false valeurs et présenter d’autres options

notre version: elle nettoie également les chaînes vides et les valeurs nulles

 class Hash def compact delete_if{|k, v| (v.is_a?(Hash) and v.respond_to?('empty?') and v.compact.empty?) or (v.nil?) or (v.is_a?(Ssortingng) and v.empty?) } end end 

Dans Simple one liner pour supprimer des valeurs nulles dans Hash,

 rec_hash.each {|key,value| rec_hash.delete(key) if value.blank? } 

Pourrait être fait avec la bibliothèque de facettes (une des fonctionnalités manquantes de la bibliothèque standard), comme ça:

 require 'hash/compact' require 'enumerable/recursively' hash.recursively { |v| v.compact! } 

Fonctionne avec tout Enumerable (y compris Array, Hash).

Regardez comment la méthode récursive est implémentée.

fonctionne à la fois pour les hachages et les tableaux

 module Helpers module RecursiveCompact extend self def recursive_compact(hash_or_array) p = proc do |*args| v = args.last v.delete_if(&p) if v.respond_to? :delete_if v.nil? || v.respond_to?(:"empty?") && v.empty? end hash_or_array.delete_if(&p) end end end 

PS basé sur quelqu’un répond, ne peut pas trouver

Je pense qu’il serait préférable d’utiliser une méthode auto-récursive. Cela va aussi loin que nécessaire. Cela supprimera la paire de valeurs de clé si la valeur est nulle ou un hachage vide.

 class Hash def compact delete_if {|k,v| v.is_a?(Hash) ? v.compact.empty? : v.nil? } end end 

Ensuite, l’utiliser ressemblera à ceci:

 x = {:a=>{:b=>2, :c=>3}, :d=>nil, :e=>{:f=>nil}, :g=>{}} # => {:a=>{:b=>2, :c=>3}, :d=>nil, :e=>{:f=>nil}, :g=>{}} x.compact # => {:a=>{:b=>2, :c=>3}} 

Pour garder des hachages vides, vous pouvez simplifier cela.

 class Hash def compact delete_if {|k,v| v.compact if v.is_a?(Hash); v.nil? } end end 
 class Hash def compact def _empty?(val) case val when Hash then val.compact.empty? when Array then val.all? { |v| _empty?(v) } when Ssortingng then val.empty? when NilClass then true # ... custom checking end end delete_if { |_key, val| _empty?(val) } end end 

Essayez ceci pour supprimer nil

 hash = { a: true, b: false, c: nil } => {:a=>true, :b=>false, :c=>nil} hash.inject({}){|c, (k, v)| c[k] = v unless v.nil?; c} => {:a=>true, :b=>false}