[英]Recursively removing `nil` and empty values from hash
I have a hash that starts out as: 我有一个哈希开头为:
{"request"=>{
"security"=>{"username"=>{"type"=>nil}, "password"=>{"type"=>nil}},
"order_i_d"=>{"type"=>nil, "description"=>nil},
"order_number"=>{"type"=>nil},
"show_kit_as_individual_s_k_us"=>false,
"website_i_d"=>{"type"=>nil, "description"=>nil}
}}
And I'd like to recursively remove all values that are nil?
我想递归地删除所有
nil?
值nil?
and empty?
empty?
but leave the falsey
values in place. 但离开
falsey
到位值。 The final result should look like: 最终结果应如下所示:
{"request"=>{
"show_kit_as_individual_s_k_us"=>false
}}
How can I accomplish this? 我该怎么做?
Just another implementation, written for fun & practice. 只是为了娱乐和练习而编写的另一个实现。
DeepCompact.deep_compact(hash)
DeepCompact.deep_compact(hash)
DeepCompact.deep_compact!(hash)
DeepCompact.deep_compact!(hash)
{ foo: nil }.extend(DeepCompact).deep_compact
{ foo: nil }.extend(DeepCompact).deep_compact
using DeepCompact
to a file/class will bring deep_compact
and deep_compact!
using DeepCompact
: using DeepCompact
添加到文件/类将带来deep_compact
和deep_compact!
to Hashes and Arrays for all code in that file/class. Here's the module: 这是模块:
module DeepCompact
[Hash, Array].each do |klass|
refine klass do
def deep_compact
DeepCompact.deep_compact(self)
end
def deep_compact!
DeepCompact.deep_compact!(self)
end
end
end
def self.extended(where)
where.instance_exec do
def deep_compact
DeepCompact.deep_compact(self)
end
def deep_compact!
DeepCompact.deep_compact!(self)
end
end
end
def deep_compact(obj)
case obj
when Hash
obj.each_with_object({}) do |(key, val), obj|
new_val = DeepCompact.deep_compact(val)
next if new_val.nil? || (new_val.respond_to?(:empty?) && new_val.empty?)
obj[key] = new_val
end
when Array
obj.each_with_object([]) do |val, obj|
new_val = DeepCompact.deep_compact(val)
next if new_val.nil? || (new_val.respond_to?(:empty?) && new_val.empty?)
obj << val
end
else
obj
end
end
module_function :deep_compact
def deep_compact!(obj)
case obj
when Hash
obj.delete_if do |_, val|
val.nil? || (val.respond_to?(:empty?) && val.empty?) || DeepCompact.deep_compact!(val)
end
obj.empty?
when Array
obj.delete_if do |val|
val.nil? || (val.respond_to?(:empty?) && val.empty?) || DeepCompact.deep_compact!(val)
end
obj.empty?
else
false
end
end
module_function :deep_compact!
end
And then some examples on how to use it: 然后是一些有关如何使用它的示例:
hsh = {
'hello' => [
'world',
{ 'and' => nil }
],
'greetings' => nil,
'salutations' => {
'to' => { 'you' => true, 'him' => 'yes', 'her' => nil },
'but_not_to' => nil
}
}
puts "Original:"
pp hsh
puts
puts "Non-destructive module function:"
pp DeepCompact.deep_compact(hsh)
puts
hsh.extend(DeepCompact)
puts "Non-destructive after hash extended:"
pp hsh.deep_compact
puts
puts "Destructive refinement for array:"
array = [hsh]
using DeepCompact
array.deep_compact!
pp array
And the output: 并输出:
Original:
{"hello"=>["world", {"and"=>nil}],
"greetings"=>nil,
"salutations"=>
{"to"=>{"you"=>true, "him"=>"yes", "her"=>nil}, "but_not_to"=>nil}}
Non-destructive module function:
{"hello"=>["world"], "salutations"=>{"to"=>{"you"=>true, "him"=>"yes"}}}
Non-destructive after hash extended:
{"hello"=>["world"], "salutations"=>{"to"=>{"you"=>true, "him"=>"yes"}}}
Destructive refinement for array:
[{"hello"=>["world"], "salutations"=>{"to"=>{"you"=>true, "him"=>"yes"}}}]
Or just use one of the multiple gems that provide this for you. 或仅使用为您提供此功能的多个宝石之一。
Came up with the following: 提出以下建议:
class Hash
def deep_compact!
self.each_pair do |key, value|
if value.is_a?(Hash)
value.deep_compact!
end
if value.nil? || (value.is_a?(Hash) && value.empty?)
self.delete(key)
end
end
end
end
Another option: 另外一个选项:
class Hash
def deep_transform(&block)
self.inject({}){|result, (key,value)|
value = if Hash === value
value.deep_transform(&block)
else
value
end
block.call(result,key,value)
result
}
end
def deep_compact
self.deep_transform do |result, key, value|
if value.nil? || (value.is_a?(Hash) && value.empty?)
# Don't Keep
else
result[key] = value
end
end
end
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.