How would I go about removing all empty elements (empty list items) from a nested Hash or YAML file?
Ruby's Hash#compact, Hash#compact! and Hash#delete_if! do not work on nested nil, empty? and/or blank? values. Note that the latter two methods are destructive, and that all nil, "", false, [] and {} values are counted as blank?.
Hash#compact and Hash#compact! are only available in Rails, or Ruby version 2.4.0 and above.
Here's a non-destructive solution that removes all empty arrays, hashes, strings and nil values, while keeping all false values:
(blank? can be replaced with nil? or empty? as needed.)
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
A destructive version:
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
Or, if you want to add both versions as instance methods on the Hash class:
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
Other options:
v.blank? && v != false with v.nil? || v == "" to strictly remove empty strings and nil valuesv.blank? && v != false with v.nil? to strictly remove nil valuesEDITED 2017/03/15 to keep false values and present other options