在ruby中深层紧凑的嵌套哈希?

时间:2016-10-27 16:29:58

标签: ruby-on-rails ruby hash

给出以下哈希结构......

{
  a: nil,
  b: [],
  c: {c1: {c2: nil}},
  d: [{d1: "Value!"}],
  e: "Value!",
  f: {f1: {f2: nil, f3: "Value!"}}
}

我希望能够回来......

{
  d: [{d1: "Value!"}],
  e: "Value!",
  f: {f1: {f3: "Value!"}}
}

所以规则是
  1)删除任何指向nil{}[]值的键   2)删除任何指向值为空的值的键(原始哈希中的示例c:
  3)如果一个或多个内部键指向非空值,则保留外键,但删除指向空值的内部键。 (请参阅f:并注意f2:已删除)

任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:1)

你可以通过猴子修补所涉及的核心课程获得一些乐趣:

class Object
  def crush
    self
  end
end

class Array
  def crush
    r = map(&:crush).compact

    r.empty? ? nil : r
  end
end

class Hash
  def crush
    r = each_with_object({ }) do |(k, v), h|
      if (_v = v.crush)
        h[k] = _v
      end
    end

    r.empty? ? nil : r
  end
end

这是一件不寻常的事情,但如果确实需要这样做,那么编写像crush这样的方法可能有所帮助。

答案 1 :(得分:1)

这应该是适用于嵌套数组和哈希的单次通过操作:

def crush(thing)
  if thing.is_a?(Array)
    thing.each_with_object([]) do |v, a|
      v = crush(v)
      a << v unless [nil, [], {}].include?(v)
    end
  elsif thing.is_a?(Hash)
    thing.each_with_object({}) do |(k,v), h|
      v = crush(v)
      h[k] = v unless [nil, [], {}].include?(v)
    end
  else
    thing
  end

end

答案 2 :(得分:0)

  def deep_compact(hash)
    res_hash = hash.map do |key, value|
      value = deep_compact(value) if value.is_a?(Hash)

      value = nil if [{}, []].include?(value)
      [key, value]
    end

    res_hash.to_h.compact
  end