我该如何从嵌套的哈希或 YAML 文件中删除所有空元素(空列表项)?
Hash#compact
、Hash#compact!
和Hash#delete_if!
方法无法处理嵌套的nil
、empty?
和/或blank?
值。请注意,后两种方法是具有破坏性的,并且所有的nil
、""
、false
、[]
和{}
值都被视为blank?
。
Hash#compact
和Hash#compact!
仅在Rails或Ruby版本2.4.0及以上可用。nil
值,同时保留所有false
值:blank?
可以根据需要替换为nil?
或empty?
。)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
其他选项:
v.blank? && v != false
替换为v.nil? || v == ""
以严格删除空字符串和nil
值v.blank? && v != false
替换为v.nil?
以严格删除nil
值编辑于2017/03/15,保留false
值并提供其他选项。
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
在哈希表中删除空值的简单一行代码:
rec_hash.each {|key,value| rec_hash.delete(key) if value.blank? }
https://dev59.com/CXA75IYBdhLWcg3wJFgL#14773555的递归版本是可行的,但是不能与HashWithIndifferentAccess
或其他类似哈希的类一起使用。
以下是我正在使用的版本:
def recursive_compact
inject({}) do |new_hash, (k,v)|
if !v.nil?
new_hash[k] = v.kind_of?(Hash) ? v.recursive_compact : v
end
new_hash
end
end
kind_of?(Hash)
可以接受更多类似于Hash的类。
如果您想使用符号和字符串访问新哈希表,还可以将inject({})
替换为inject(HashWithIndifferentAccess.new)
。
我认为最好使用自递归方法。这样它可以深入到需要的程度。如果值为nil或空哈希,则会删除键值对。
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
compact
和 transform_values
方法,因此您可以这样做:class Hash
def deep_compact
compact.transform_values{|vl| vl.is_a?(Hash) ? vl.deep_compact : vl }
end
end
在我看来,这是最整洁的实现。
这是我拥有的东西:
# recursively remove empty keys (hashes), values (array), hashes and arrays from hash or array
def sanitize data
case data
when Array
data.delete_if { |value| res = sanitize(value); res.blank? }
when Hash
data.delete_if { |_, value| res = sanitize(value); res.blank? }
end
data.blank? ? nil : data
end
# returns new instance of hash with deleted nil values
def self.deep_remove_nil_values(hash)
hash.each_with_object({}) do |(k, v), new_hash|
new_hash[k] = deep_remove_nil_values(v) if v.is_a?(Hash)
new_hash[k] = v unless v.nil?
end
end
# rewrite current hash
def self.deep_remove_nil_values!(hash)
hash.each do |k, v|
deep_remove_nil_values(v) if v.is_a?(Hash)
hash.delete(k) if v.nil?
end
end
blank?
也适用于空字符串。 - Hertzel Guinness