【问题标题】:Overwrite sub-object in Ruby hash覆盖 Ruby 哈希中的子对象
【发布时间】:2015-07-16 06:00:39
【问题描述】:

我有一个嵌套的哈希,比如说:

data = {
  a: {
    b: {
      c: {
        d: {
          e: :f
        }
      }
    }
  }
}

另一个哈希:

update = {g: :h}

还有一条路径:

path = [:a, :b, :c, :d]

我想将path指定的data的子哈希替换为update,这样我最终得到:

data == {
  a: {
    b: {
      c: {
        d: {
          g: :h
        }
      }
    }
  }
}

很容易导航到子哈希:

_data = data
path.each{|p| _data = data[p]}

但这不起作用,因为_data = update 改变了_data 所指的内容,并且实际上并没有改变data[:a][:b][:b][:d] 的值。

虽然我可以编写导致子哈希的表达式,但尝试分配它会导致语法错误:

> (path.inject(data){|_data, s| _data[s]}) = update
SyntaxError: unexpected '=', expecting end-of-input

有什么想法吗?

【问题讨论】:

    标签: ruby hash


    【解决方案1】:

    您可以使用Hash#replace

    > path.inject(data){|_data, s| _data[s]}.replace({g: :h})
    > data
    # => {:a=>{:b=>{:c=>{:d=>{:g=>:h}}}}} 
    

    【讨论】:

    • 啊,不,我需要删除 :e 键/值对。对不起! (否则,deep_merge 就可以了)
    • @Narfanator 可能想要Hash#replace
    • 你也可以写path[0...-1].inject(data){|_data, s| _data[s]}[path[-1]] = {g: :h}
    【解决方案2】:

    构建嵌套哈希的更新副本的递归解决方案 (Ruby 1.8.7)。

    def substitute(data, path, update)
      if path.empty? 
        update
      else
        first, *rest = path
        Hash[*data.map { |k, v| first == k ? [k, substitute(v, rest, update)] : [k ,v] }.flatten]
      end
    end
    
    result = substitute(data, path, update)
    puts "In  #{data.inspect}"   # => In  {:a=>{:b=>{:c=>{:d=>{:e=>:f}}}}}
    puts "Out #{result.inspect}" # => Out {:a=>{:b=>{:c=>{:d=>{:g=>:h}}}}}
    

    【讨论】:

    • 读得很好。我认为first, *rest = path 值得额外的代码行和两个变量的创建。
    【解决方案3】:
    def substitute(data, path, update)
      (data[path.first] = update; return) if path.size == 1
      substitute(data[path.first], path.drop(1), update)
    end
    
    substitute(data, path, update)
      #=> nil
    data
      #=> {:a=>{:b=>{:c=>{:d=>{:g=>:h}}}}} 
    

    要返回data(以及修改它),请将data 添加到最后一行。

    【讨论】:

    • 不错的递归版本。您可以使用first/drop(1) 而不是shift 来避免dup/对path 的修改。
    • @sschmeck,谢谢。我编辑了。我最初有path.firstpath[1..-1],但无法让自己使用那么丑陋的东西。 path.drop(1) 不那么丑。
    猜你喜欢
    • 1970-01-01
    • 2014-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-22
    • 1970-01-01
    • 2019-10-04
    • 2017-05-02
    相关资源
    最近更新 更多