如何递归地从(YAML)散列中删除所有具有空值的键?
我一直试图摆脱我的YAML文件中有空(空)值或空散列作为值的所有散列键。如何递归地从(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"}
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"}
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) }
你拼写错误,你的代码不解析 – 2014-04-02 13:40:15
@AbePetrillo,necromncer;) – fl00r 2014-04-02 18:39:34
只是有点相关的事情。如果你想从嵌套哈希删除指定的键:
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
。您还可以自定义其进一步
我知道这个线程是有点老,但我想出了一个更好的解决方案,它支持多维哈希值。它使用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
在发布复制和粘贴样板/逐字回答多个问题时要小心,这些问题往往会被社区标记为“垃圾”。如果你这样做,那么它通常意味着问题是重复的,所以将它们标记为:http://stackoverflow.com/a/12360142/419 – Kev 2012-09-10 23:26:18
这里有一个更通用的方法:
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 }
我觉得这是最正确的版本:
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}
你能解释它是如何工作的吗? – 2015-01-23 21:13:42
@DavidWest 'p'是一个递归的'proc'; 如果值'v'是一个类似地图的对象(响应'delete_if'),那么我们修剪其中的所有空值; 如果'v'为空(或'nil'值),那么我们删除它(返回'true'到'delete_if')。 这个解释够了吗? :) – Iazel 2015-01-25 11:33:58
非常优雅。我很佩服。我不熟悉&符号。为什么使用?阅读完本书后,我将更多地关注procs。是否有关键字可用于了解有关&符号的更多信息?它是否像使用&block一样? – 2015-01-26 01:29:43
我的版本(导轨): 类哈希 高清delete_blank delete_if { | k,v | v.blank?或(v.instance_of?(Hash)&& v.delete_blank.empty?)} end end – 2011-09-13 12:20:20
User blank?而不是空的?因为它会在零 – msroot 2014-07-02 00:23:09
失败你为什么使用delete_if而不是拒绝? – Donato 2016-03-21 21:30:15