【问题标题】:Ruby: Deleting all instances of a particular key from hash of hashesRuby:从哈希哈希中删除特定键的所有实例
【发布时间】:2012-05-20 19:43:08
【问题描述】:

我有一个类似的哈希

h = {1 => {"inner" => 45}, 2 => {"inner" => 46}, "inner" => 47}

如何删除包含“inner”键的每一对?
可以看到有些“内”对直接出现在h中,而另一些成对出现在h

请注意,我只想删除“内部”对,所以如果我在上面的哈希上调用我的批量删除方法,我应该得到

h = {1 => {}, 2 => {}}

因为这些对没有键 == "inner"

【问题讨论】:

  • 先从h中删除“inner”,然后递归遍历所有嵌套的hash并删除“inner”

标签: ruby


【解决方案1】:

真的,这就是拒绝!适用于:

def f! x
  x.reject!{|k,v| 'inner' == k} if x.is_a? Hash
  x.each{|k,v| f! x[k]}
end

【讨论】:

    【解决方案2】:
    def f x 
      x.inject({}) do |m, (k, v)|
        v = f v if v.is_a? Hash  # note, arbitrarily recursive
        m[k] = v unless k == 'inner'
        m
      end
    end
    
    p f h
    

    更新:略有改进...

    def f x
      x.is_a?(Hash) ? x.inject({}) do |m, (k, v)|
        m[k] = f v unless k == 'inner'
        m
      end : x
    end
    

    【讨论】:

    • 多行三进制与inject 的块形式相结合,使您改进后的解决方案难以阅读(尤其是当您将这些解决方案与使用单字母、非描述性方法和变量名结合使用时)。如果您使用 if/else 而不是三元且有意义的变量名称,那么会更容易理解: ``` def reject_keys(input, denied_key) if input.is_a?(Hash) input.inject({})做 |散列, (k, v)| hash[k] = reject_keys(v) unless k == denied_key hash end else input end end puts reject_keys(h, "inner") ``
    【解决方案3】:
    def except_nested(x,key)
      case x
      when Hash then x = x.inject({}) {|m, (k, v)| m[k] = except_nested(v,key) unless k == key ; m }
      when Array then x.map! {|e| except_nested(e,key)}
      end
      x
    end
    

    【讨论】:

    • 我实际上一直需要这个解决方案,因为我也有嵌套数组!非常感谢!
    • 这是唯一对我有用的。谢谢。
    【解决方案4】:

    这是我想出的:

    class Hash
      def deep_reject_key!(key)
        keys.each {|k| delete(k) if k == key || self[k] == self[key] }
    
        values.each {|v| v.deep_reject_key!(key) if v.is_a? Hash }
        self
      end
    end
    

    适用于 Hash 或 HashWithIndifferentAccess

    > x = {'1' => 'cat', '2' => { '1' => 'dog', '2' => 'elephant' }}
    => {"1"=>"cat", "2"=>{"1"=>"dog", "2"=>"elephant"}}
    
    > y = x.with_indifferent_access
    => {"1"=>"cat", "2"=>{"1"=>"dog", "2"=>"elephant"}}
    
    > x.deep_reject_key!(:"1")
    => {"1"=>"cat", "2"=>{"1"=>"dog", "2"=>"elephant"}}
    
    > x.deep_reject_key!("1")
    => {"2"=>{"2"=>"elephant"}}
    
    > y.deep_reject_key!(:"1")
    => {"2"=>{"2"=>"elephant"}}
    

    【讨论】:

      【解决方案5】:

      类似的答案,但它是一种白名单类型的方法。对于 ruby​​ 1.9+

      # recursive remove keys
      def deep_simplify_record(hash, keep)
        hash.keep_if do |key, value|
          if keep.include?(key) 
            deep_simplify_record(value, keep) if value.is_a?(Hash)
            true
          end
        end
      end
      
      hash = {:a => 1, :b => 2, :c => {:a => 1, :b => 2, :c => {:a => 1, :b => 2, :c => 4}} }
      deep_simplify_record(hash, [:b, :c])
      # => {:b=>2, :c=>{:b=>2, :c=>{:b=>2, :c=>4}}}
      

      这里还有一些我喜欢用于哈希的其他方法。 https://gist.github.com/earlonrails/2048705

      【讨论】:

      • 有一个极端情况:h = {a: 1, b: {c: 1, a: {b: 2}}}; deep_simplify_record(h, %i[b c]) 产生{:b=>{:c=>1, :a=>{:b=>2}}}。并非所有:as 都被删除。无论v 是否为Hash,都需要检查include?
      猜你喜欢
      • 2015-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-25
      • 1970-01-01
      • 2021-10-19
      • 1970-01-01
      相关资源
      最近更新 更多