在特定位置插入哈希条目

时间:2016-02-20 07:24:21

标签: ruby hash

给出哈希:

{"set_filter"=>["0"], "test1"=>["=test1"], "test2"=>["=test2"]}

如何在set_filter条目后添加新的键值对?预期的输出应该是这样的:

{
  "set_filter" => ["0"],
  "test3" => ["=test3"],
  "test1" => ["=test1"],
  "test2" => ["=test2"]
}

我想在哈希中的某个位置插入一个新的键值对。

3 个答案:

答案 0 :(得分:6)

唯一的哈希提供的顺序是插入顺序,并且只影响迭代。所以你不能真正添加一个特定的元素,除非你愿意删除所有跟随它的插入,然后再插入所有那些元素。

相反,您可能希望使用一对数组,如下所示:

A = [["set_filter", "0"], ...]

然后使用Array#insert,就像这样

A.insert(2, ["test3", "=test3"])

当订单很重要时,请使用该数组。 当您需要哈希界面时,您可以

A.to_h # yields { 'set_filter' => '0', ... }

答案 1 :(得分:2)

我建议你做以下事情:

  • 从哈希中提取密钥并找到给定密钥的索引
  • 如果要在给定键
  • 之后而不是之前插入给定对,则向索引添加一个
  • 将哈希转换为数组
  • 在计算索引之前插入数组(如果索引等于数组的大小,则在最后一对之后)
  • 将生成的数组转换回哈希

def insert_pair(h, key, pair, proximity=:before)
  h.to_a.insert(h.keys.index(key) + (proximity==:after ? 1 : 0), pair.first).to_h
end

h = {"set_filter"=>["0"], "test1"=>["=test1"], "test2"=>["=test2"]}
pair = {"test3"=>["=test3"]}

insert_pair(h, "set_filter", pair, :after)
  #=> {"set_filter"=>["0"], "test3"=>["=test3"], "test1"=>["=test1"], "test2"=>["=test2"]} 
insert_pair(h, "set_filter", pair)
  #=> {"test3"=>["=test3"], "set_filter"=>["0"], "test1"=>["=test1"], "test2"=>["=test2"]} 
insert_pair(h, "test2",      pair, :after)
  #=> {"set_filter"=>["0"], "test1"=>["=test1"], "test2"=>["=test2"], "test3"=>["=test3"]} 

我已:before默认为Array#insert

这是一种替代方法,它不会将哈希值转换为数组,修改数组然后将其转换回哈希值。相反,它将现有哈希分成两个哈希,在它们之间滑动单键哈希,然后将所有三个哈希合并为一个哈希。

def insert_pair(h, key, pair, proximity=:before)
  keys = h.keys
  before_keys =
  case proximity
  when :before
    key==keys.first ? [[], keys] : keys.slice_before { |k| k == key }
  when :after
    keys.slice_after { |k| k == key }
  end.first
  h.select { |k,_| before_keys.include? k }.
    update(pair).
    update(h.reject { |k,_| before_keys.include? k }) 
end

insert_pair(h, "set_filter", pair, :after)
  #=> {"set_filter"=>["0"], "test3"=>["=test3"], "test1"=>["=test1"], "test2"=>["=test2"]} 
insert_pair(h, "set_filter", pair)
  #=> {"test3"=>["=test3"], "set_filter"=>["0"], "test1"=>["=test1"], "test2"=>["=test2"]} 
insert_pair(h, "test2",      pair, :after)
  #=> {"set_filter"=>["0"], "test1"=>["=test1"], "test2"=>["=test2"], "test3"=>["=test3"]} 

答案 2 :(得分:1)

对@cary的回答略有改进(我会直接对其进行评论,但我的声誉不足)。

如果您希望一次插入多个哈希键(带有多个键的pair),则可以使用@cary变体一的以下修改形式:

def insert_pair(h, key, pair, proximity=:before)
  h.to_a.insert(h.keys.index(key) + (proximity==:after ? 1 : 0), *pair.to_a).to_h
end

h = {"set_filter"=>["0"], "test1"=>["=test1"], "test2"=>["=test2"]}

#insert pair with one hash key
pair = {"test3"=>["=test3"]}
insert_pair(h, "set_filter", pair, :after)
  #=> {"set_filter"=>["0"], "test3"=>["=test3"], "test1"=>["=test1"], "test2"=>["=test2"]} 

#insert pair with >1 hash keys
pair = {"test3"=>["=test3"], "test4" => ["=test4"], "test5" => ["=test5"]}
insert_pair(h, "set_filter", pair, :after)
  #=> {"set_filter"=>["0"], "test3"=>["=test3"], "test4" => ["=test4"], "test5 => ["=test5"], "test1"=>["=test1"], "test2"=>["=test2"]} 

注意pair可以是一个或多个哈希键,因此这不会破坏原始用例,而只是扩展了它。