如何从(YAML)哈希中递归删除所有具有空值的键?

发布于 2024-11-06 21:19:09 字数 608 浏览 0 评论 0原文

我一直在尝试删除 YAML 文件中具有空(空白)值或空哈希值的所有哈希键。

这篇之前的帖子帮助我几乎正确,但是每当有足够深的嵌套时,递归单行代码就会在我的 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"}

I have been trying to get rid of all hash keys in my YAML file that have empty (blank) values or empty hashes as values.

This earlier post helped me to get it almost right, but the recursive one-liner leaves my YAML dump with empty hashes whenever there is sufficiently deep nesting.

I would really appreciate any help on this. Thanks!

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)

Actual output

 {"x"=>{"m"=>{}}, "y"=>"content"} 

Desired output

{"y"=>"content"}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

陪我终i 2024-11-13 21:19:10

我认为这是最正确的版本:

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}

I think this the most correct version:

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}
月朦胧 2024-11-13 21:19:10

我知道这个线程有点旧,但我想出了一个更好的解决方案,支持多维哈希。它使用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

I know this thread is a bit old but I came up with a better solution which supports Multidimensional hashes. It uses delete_if? except its multidimensional and cleans out anything with a an empty value by default and if a block is passed it is passed down through it's children.

# 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
纸伞微斜 2024-11-13 21:19:10

只是有点相关的事情。如果你想从嵌套哈希中删除指定的键:

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

。你也可以进一步自定义它

Just a bit related thing. If you want to delete specified keys from nested hash:

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

.You can also customize it further

绮筵 2024-11-13 21:19:10
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建议的那样,你可以使用这个过程

clean = proc{ |k,v| v.empty? or Hash === v && v.delete_if(&clean) }
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"} 

or like @sawa suggested, you can use this proc

clean = proc{ |k,v| v.empty? or Hash === v && v.delete_if(&clean) }
落花浅忆 2024-11-13 21:19:09
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"}
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"}
随波逐流 2024-11-13 21:19:09

这是一个更通用的方法:

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 }

Here's a more generic method:

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 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文