Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to recursively remove all keys with empty values from (YAML) hash?

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"}
like image 672
juwalter Avatar asked May 12 '11 08:05

juwalter


3 Answers

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"}
like image 188
sawa Avatar answered Nov 16 '22 01:11

sawa


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 }
like image 45
code_monkey_steve Avatar answered Nov 16 '22 03:11

code_monkey_steve


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}
like image 26
Iazel Avatar answered Nov 16 '22 01:11

Iazel