从哈希/ YAML中删除所有空元素?
我将如何去除嵌套散列或YAML文件中的所有空元素(空列表项)?
你可以添加一个紧凑的方法哈希像这样
class Hash def compact delete_if { |k, v| v.nil? } end end
或者支持recursion的版本
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
使用hsh.delete_if 。 在你的具体情况下,如: hsh.delete_if { |k, v| v.empty? }
hsh.delete_if { |k, v| v.empty? }
Rails 4.1增加了Hash#compact和Hash#compact! 作为Ruby的Hash
类的核心扩展。 你可以像这样使用它们:
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 # => {}
单挑:这个实现不是recursion的。 作为好奇心,他们使用#select
而不是#select
来实现它,出于性能原因。 看这里的基准 。
如果你想将它回溯到你的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
这个也会删除空的哈希值:
swoop = Proc.new { |k, v| v.delete_if(&swoop) if v.kind_of?(Hash); v.empty? } hsh.delete_if &swoop
我知道这个线程是有点老,但我想出了一个更好的解决scheme,支持多维哈希。 它使用delete_if? 除了它的多维外,默认情况下用空值清除任何东西,如果一个块被传递,则它通过它的子元素传递。
# 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
我做了一个deep_compact方法,recursion地过滤掉nillogging(也可以是空白logging):
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
您可以使用哈希#拒绝从ruby哈希中删除空的键/值对。
# Remove empty strings { 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 strings {a: '', b: nil, c: 'third'}.reject { |k,v| v.nil? || v.empty? } # => {:c=>"third"}
我们的版本:它也清理空string和零值
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?(String) and v.empty?) } end end
在简单的一个线程删除Hash中的空值,
rec_hash.each {|key,value| rec_hash.delete(key) if value.blank? }
可以用facet库(标准库中缺less的特征)来完成,就像这样:
require 'hash/compact' require 'enumerable/recursively' hash.recursively { |v| v.compact! }
适用于任何Enumerable(包括Array,Hash)。
看看recursion方法是如何实现的。
Ruby的Hash#compact
, Hash#compact!
和Hash#delete_if!
不要在嵌套的nil
上工作, empty?
和/或blank?
值。 请注意,后两种方法具有破坏性,并且所有nil
, ""
, false
, []
和{}
值计为blank?
。
Hash#compact
和Hash#compact!
仅在Rails或Ruby版本2.4.0及以上版本中可用。
这是一个非破坏性的解决scheme,它可以删除所有空数组,哈希,string和nil
值,同时保留所有false
值:
(根据需要, blank?
可以用empty?
或empty?
来replace。)
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
破坏版本:
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
或者,如果您想在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
其他选项:
- replace
v.blank? && v != false
v.blank? && v != false
与v.nil? || v == ""
v.nil? || v == ""
v.nil? || v == ""
严格删除空string和nil
值 - replace
v.blank? && v != false
v.blank? && v != false
与v.nil?
严格删除nil
值 - 等等。
编辑2017/03/15保留false
价值,并提出其他select
我相信最好使用自recursion方法。 这样它就可以根据需要进行深入。 这将删除键值对,如果值为零或空的散列。
class Hash def compact delete_if {|k,v| v.is_a?(Hash) ? v.compact.empty? : v.nil? } end end
然后使用它将看起来像这样:
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}}
为了保持空的散列,你可以简化它。
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 String then val.empty? when NilClass then true # ... custom checking end end delete_if { |_key, val| _empty?(val) } end end
试试这个删除零
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}