以递归方式删除具有空值的哈希值

时间:2015-08-04 23:36:35

标签: ruby hash

我想删除不同嵌套级别的空哈希。一旦删除了空哈希,我也想删除它的容器哈希。我该怎么做?

这是我想要处理的哈希:

{
  "query"=>{"filtered"=>{
    "query"=>{"bool"=>{}},
    "filter"=>{"query"=>{"query_string"=>{
      "fields"=>[["standard_analyzed_name", "standard_analyzed_message"]],
      "query"=>"Arnold AND Schwarz"
    }}}
  }},
  "sort"=>[{"total_interactions"=>{"order"=>"desc"}}]
}

以下是我没有删除空{"query"=>{"bool"=>{}}部分的代码:

def compactify_hash(main_hash)
  main_hash.each do |key, value|
    if(value.class == Hash && !value.empty?)
      compactify_hash(value)
    elsif(value.class == Hash && value.empty?)
      main_hash.delete(key)
    end
  end
  return main_hash
end

2 个答案:

答案 0 :(得分:4)

这里有一些问题:

  1. 如果你真的想要在适当的位置修改它,你可能想要为你的方法compactify_hash!命名。
  2. 你的哈希中有阵列,但你没有扫描它们是否有空哈希。
  3. 最重要的是,你永远不会检查你的递归​​紧凑哈希值,看看是否压缩了它们还清空了它们。在这里:

    if(value.class == Hash && !value.empty?)
        compactify_hash(value)
    elsif(value.class == Hash && value.empty?)
        main_hash.delete(key)
    end
    

    您需要在 value.empty?之后检查compactify_hash(value)

  4. 你可以这样做:

    def compactify_hash(main_hash)
        main_hash.each_with_object({}) do |(k, v), h|
            if(v.is_a?(Hash))
                ch = compactify_hash(v)
                h[k] = ch if(!ch.empty?)
            elsif(v.is_a?(Array))
                h[k] = v.map do |e|
                    e.is_a?(Hash) ? compactify_hash(e) : e
                end
            else
                h[k] = v
            end
        end
    end
    

答案 1 :(得分:3)

我假设对于任何哈希h,您希望创建另一个哈希g,它与h相同,但g中没有嵌套哈希将具有键值对[k,v]v.respond_to(:empty?)v.empty?都返回true。例如,如果h中存在以下嵌套哈希:

{ a: { b: '', c: {}, d: [] }, e: 3 }

然后g中相应的嵌套哈希将是:

{ e: 3 }

实际上,我们会“删除”键值对:b=> '':c=> {}:d=> [],因为''{}[]所有人都回复:empty?并且都是空的。这会将嵌套哈希减少为:

{ a: {}, e: 3 }

由于a的值现在为空,我们删除该键值对,使g中的嵌套哈希值等于:

{ e: 3 }

我相信这可以通过以下方式实现:

def remove(h)
  loop do
    h_new = remove_empties(h)
    break h if h==h_new
    h = h_new
  end
end

def remove_empties(h)
  h.each_with_object({}) do |(k,v),g|
    case v
    when Hash
      g[k] = remove_empties(h[k]) unless v.empty? 
    else
      g[k] = v unless v.respond_to?(:empty?) && v.empty?
    end
  end
end

对于您的哈希,我将其称为h

remove(h)
  #=> {:query=>
  #      {:filtered=>
  #        {:filter=>
  #          {:query=>
  #            {:query_string=>
  #              {:fields=>
                   [["standard_analyzed_name", "standard_analyzed_message"]],
  #               :query=>"Arnold AND Schwarz"
  #              }
  #            }
  #          }
  #        }
  #      },
  #    :sort=>[
  #             {:total_interactions=>
  #               {:order=>"desc"}
  #             }
  #           ]
  #  }

请注意,重复执行递归,直到不再执行散列修改。