Ruby无法将值映射到散列数组,搜索替代

时间:2017-01-03 12:53:33

标签: ruby-on-rails ruby ruby-on-rails-4

我有一系列哈希:

data1 = [{:first => 1, :second => 'whatever'},{:first => 2, :second => 'something'}]

test_merge = {'whatever' => {:third => 1, :fourth => 1}, 'something' => {:third => 2, :fourth => 2}}

我想要这个输出:

[{:first=>"MODIFIED", :second=>"whatever", :test_field=>"added", :third=>1, :fourth=>1, "sdsds"=>"sdsds", "2x4"=>8}, {:first=>"MODIFIED", :second=>"something", :test_field=>"added", :third=>2, :fourth=>2, "sdsds"=>"sdsds", "2x4"=>8}]

我做了地图和合并:

data2 = data1.map do |d|
    d[:test_field] = 'added'
    d[:first] = 'MODIFIED'
    d2 = test_merge[d[:second]]
    d = d.merge(d2)
    d['sdsds'] = 'sdsds'
    d['2x4'] = 2*4
  end

我得到了:

data1 #=> [{:first=>"MODIFIED", :second=>"whatever", :test_field=>"added"}, {:first=>"MODIFIED", :second=>"something", :test_field=>"added"}]
data2 #=> [8, 8]

如果我这样做可以修复

data2 = data1.map do |d|
        d[:test_field] = 'added'
        d[:first] = 'MODIFIED'
        d2 = {:test_field_two => 'notadded'}
        d = d.merge(d2)
        d['sdsds'] = 'sdsds'
        d['2x4'] = 2*4
        d #or d=d
end

但为什么我必须在最后dd插入d=d?最后写d看起来很难看。是不是有另一种方法可以做到,我想要如上所述的确切输出?

编辑:2017年1月3日(如果您是第一次阅读此问题,请不要阅读此编辑内容,上面提到了所有内容)

我必须在.map中使用merge,因为我有另一个哈希如下:

test_merge = {'whatever' => {:third => 1, :fourth => 1}, 'something' => {:third => 2, :fourth => 2}}

需要在.each中合并这样(合并在.each中不起作用,所以我必须使用map)或.map

d = d.merge(test_merge[d[:second]])

此外,'2x4':first和其他密钥也很重要,需要设置/修改。

如果我需要修改d [:first],它应该被修改。

我试过史蒂夫提到的.each

data1 = [{:first => 1, :second => 'whatever'},{:first => 2, :second => 'something'}]

    test_merge = {'whatever' => {:third => 1, :fourth => 1}, 'something' => {:third => 2, :fourth => 2}}
      data1.each do |d|
        d[:test_field] = 'added'
        d[:first] = 'MODIFIED'
        d2 = test_merge[d[:second]]
        d = d.merge(d2)
        d['sdsds'] = 'sdsds'
        d['2x4'] = 2*4
      end

这是我得到的结果:

[{:first=>"MODIFIED", :second=>"whatever", :test_field=>"added"}, {:first=>"MODIFIED", :second=>"something", :test_field=>"added"}]

这不是我预期的输出。这有什么黑客攻击吗?

3 个答案:

答案 0 :(得分:3)

使用块执行map时,块的最后执行行是在新数组中返回的内容。

所以如果最后一行是......

d['2x4'] = 2*4

然后它返回了2 * 4(8)。

将块的最后一行设置为...

d

...表示返回d变量(整个哈希)的值。

如果您只想更改哈希值并且不需要返回数组,则不需要使用map。请改用each。 (编辑时考虑到Eric关于浅层复制的观察结果)。

data2 = data1.map{|d| d.dup}
data2.each do |d|
  d[:test_field] = 'added'
  d[:test_field_two] = 'notadded'
  d['sdsds'] = 'sdsds'
  d['2x4'] = 2*4
end

答案 1 :(得分:1)

Hash#merge返回合并的Hash而不更改原始的Hash,因此您可以添加新的|key,value|对并直接返回所需的哈希:

data2 = data1.map do |h1|
  h1.merge(:test_field     => 'added',
           :test_field_two => 'not_added',
           'sdsds'         => 'sdsds',
           '2x4'           => 2 * 4)
end

data2现在是:

[{:first=>1,
  :second=>"whatever",
  :test_field=>"added",
  :test_field_two=>"not_added",
  "sdsds"=>"sdsds",
  "2x4"=>8},
 {:first=>2,
  :second=>"something",
  :test_field=>"added",
  :test_field_two=>"not_added",
  "sdsds"=>"sdsds",
  "2x4"=>8}]

虽然data1仍然是:

[{:first=>1, :second=>"whatever"}, {:first=>2, :second=>"something"}]

答案 2 :(得分:0)

我认为这可能会更好!虽然我不确定我是否正确理解了这个问题。希望这会有所帮助。

data1 = [{:first => 1, :second => 'whatever'},{:first => 2, :second => 'something'}]

d2 = {:test_field_two => 'notadded', "sdsds"=>"sdsds", "2x4"=>2*4}

data2 = data1.map do |d| d.merge(d2) end

#=> [{:first=>1, :second=>"whatever", :test_field_two=>"notadded", "sdsds"=>"sdsds", "2x4"=>8}, {:first=>2, :second=>"something", :test_field_two=>"notadded", "sdsds"=>"sdsds", "2x4"=>8}]