我一直试图摆脱我的YAML文件中所有具有空(空白)值或空哈希值作为值的哈希键。
这个earlier post帮我把它弄得差不多,但是当有足够深的嵌套时,递归的单行为我的YAML转储留下空哈希。
我真的很感激任何帮助。谢谢!
proc = Proc.new { |k, v| (v.kind_of?(Hash) && !v.empty? ) ? (v.delete_if(&proc); nil) : v.blank? }
hash = {"x"=>{"m"=>{"n"=>{}}}, 'y' => 'content'}
hash.delete_if(&proc)
实际输出
{"x"=>{"m"=>{}}, "y"=>"content"}
期望的输出
{"y"=>"content"}
答案 0 :(得分:15)
class Hash
def delete_blank
delete_if{|k, v| v.empty? or v.instance_of?(Hash) && v.delete_blank.empty?}
end
end
p hash.delete_blank
# => {"y"=>"content"}
答案 1 :(得分:5)
这是一个更通用的方法:
class Hash
def deep_reject(&blk)
self.dup.deep_reject!(&blk)
end
def deep_reject!(&blk)
self.each do |k, v|
v.deep_reject!(&blk) if v.is_a?(Hash)
self.delete(k) if blk.call(k, v)
end
end
end
{ a: 1, b: nil, c: { d: nil, e: '' } }.deep_reject! { |k, v| v.blank? }
==> { a: 1 }
答案 2 :(得分:3)
我认为这是最正确的版本:
h = {a: {b: {c: "",}, d:1}, e:2, f: {g: {h:''}}}
p = proc do |_, v|
v.delete_if(&p) if v.respond_to? :delete_if
v.nil? || v.respond_to?(:"empty?") && v.empty?
end
h.delete_if(&p)
#=> {:a=>{:d=>1}, :e=>2}
答案 3 :(得分:1)
我知道这个线程有点旧,但我想出了一个更好的解决方案,它支持多维哈希。它使用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
答案 4 :(得分:0)
hash = {"x"=>{"m"=>{"n"=>{}}}, 'y' => 'content'}
clean = proc{ |k,v| !v.empty? ? Hash === v ? v.delete_if(&clean) : false : true }
hash.delete_if(&clean)
#=> {"y"=>"content"}
或者像@sawa建议的那样,你可以使用这个proc
clean = proc{ |k,v| v.empty? or Hash === v && v.delete_if(&clean) }
答案 5 :(得分:0)
只是有点相关的事情。如果要从嵌套哈希中删除指定的键:
def find_and_destroy(*keys)
delete_if{ |k, v| (keys.include?(k.to_s) ? true : ( (v.each { |vv| vv = vv.find_and_destroy(*keys) }) if v.instance_of?(Array) ; (v.each { |vv| vv = vv.find_and_destroy(*keys) }) if v.instance_of?(Hash); false) )}
end
。您还可以进一步自定义