Gem 有什么操作嵌套 Hash 的库?

linjunhalida · 2014年10月07日 · 最后由 knwang 回复于 2014年10月10日 · 2614 次阅读

比如实现:

data = {name: 'haha', info: {address: 'xx'}, admin: {password: 'xxxx'}}

data.select(|k, v| k == :password) == 'xxxx'
data.modify{|k, v| if k == :password ? 'filtered' : v }

操作树状的 Hash 结构。

没有吧,因为 k 在树的各个节点都可以相同,这样库的行为很难去定义了或者定义就很复杂了。

class Hash
  def modify(&block)
    map { |k, v| v.is_a?(Hash) ? v.modify(&block) : yield(k, v) } 
  end
end

data = {name: 'haha', info: {address: 'xx'}, admin: {password: 'xxxx'}}
puts data.modify {|k, v| k == :password ? 'filtered' : v }

你那两个例子就没一个能正确的。。太坑了。

最后还是自己写了一个简单的拓展:

class Hash
  # filter nested hash value by specific key
  # Example:
  #   {a: {b: 12}}.nested_filter(:b, 0) == {a: {b: 0}}
  def nested_filter(key, value)
    self.nested_modify do |k, v|
      v = value if k == key
      [k, v]
    end
  end

  # modify nested hash value
  # Example:
  #   {a: {b: 12}}.nested_modify{ |k, v| [:"#{k}1", v]} == {a1: {b1: 12}}
  def nested_modify(&block)
    result = self.map do |k, v|
      v = v.nested_modify(&block) if v.kind_of?(Hash)
      block.call(k, v)
    end
    Hash[result]
  end
end

首先,作为一个 Hash 你一般需要知道可能存在的 key。 如果 key 和 value 都是未知的,hash 的结构也是未知,那么不如用其他数据结构,比如 xml。 hash 的意义就是根据已知的 key 快速得到 value,如果你这边写了一个搜索方法,那么一开始用 hash 就不合适。

如果想快速得到某个嵌套 hash 的 value,可以用下面方法

class Hash

  def g(*args)
    child = self.send :[], args.shift
    if child
      if args.empty?
        child
      else
        child.g(*args)
      end
    else
      nil
    end
  end
end

# {:user => 
#       {:post_ids => [1,2,3]}
#  }

Array(params.g(:user, :post_ids))

当你想用一个很复杂嵌套的 Hash 的时候,很有可能更好的方案是把这样的复杂数据封装成对象,这样即使针对深层数据的操作也可以提到表面上来。

http://solnic.eu/2012/06/25/get-rid-of-that-code-smell-primitive-obsession.html

需要 登录 后方可回复, 如果你还没有账号请 注册新账号