【问题标题】:Recursively removing `nil` and empty values from hash从哈希中递归删除“nil”和空值
【发布时间】:2019-07-01 23:23:17
【问题描述】:

我有一个开头为:

{"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}
}}

我想递归删除所有 nil?empty? 值,但保留 falsey 值。最终结果应如下所示:

{"request"=>{
  "show_kit_as_individual_s_k_us"=>false
}}

我怎样才能做到这一点?

【问题讨论】:

  • 所以你已经知道你必须使用递归。将它与Hash#delete 结合使用就可以了。
  • 您是否混淆了虚假一词? falsey 表示 nil 或 false。如果你的意思是假的,那为什么不写呢?

标签: ruby recursion data-structures hash


【解决方案1】:

只是另一种实现,为娱乐和实践而编写。

  • 没有猴子补丁
  • 适用于哈希和数组
  • 可用作模块函数,如:DeepCompact.deep_compact(hash)
  • 也是一个破坏性目标修改变体:DeepCompact.deep_compact!(hash)
  • 可以通过扩展现有对象来使用:{ foo: nil }.extend(DeepCompact).deep_compact
  • 可以通过改进来使用:将using DeepCompact 添加到文件/类中会将deep_compactdeep_compact! 带到该文件/类中所有代码的哈希和数组中。

这是模块:

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

然后是一些关于如何使用它的例子:

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

还有输出:

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"}}}]

或者只使用为您提供此功能的多个 gem 之一。

【讨论】:

  • 当数组obj &lt;&lt; new_val时你在def deep_compact有错误
【解决方案2】:

想出了以下几点:

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

【讨论】:

    【解决方案3】:

    另一种选择:

    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
    

    【讨论】:

    猜你喜欢
    • 2015-11-17
    • 2011-08-23
    • 2019-01-02
    • 1970-01-01
    • 2016-07-11
    • 2016-01-06
    • 2023-04-09
    • 2013-10-09
    • 1970-01-01
    相关资源
    最近更新 更多