在哈希表中插入一个条目到特定位置

6

给定一个哈希表:

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

如何在set_filter条目后添加新的键值对?期望的输出应该类似于这样:
{
  "set_filter" => ["0"],
  "test3" => ["=test3"],
  "test1" => ["=test1"],
  "test2" => ["=test2"]
}

我希望在哈希表的特定位置插入一个新的键-值对。
3个回答

6
唯一的散列提供的顺序是插入顺序,这只影响迭代。因此,您实际上不能在特定元素后“添加”,除非您愿意删除其后面的所有元素,然后插入它,然后再将所有元素插入回来。
相反,您可能希望使用成对的数组,如下所示:
A = [["set_filter", "0"], ...]

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

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

当顺序很重要时,请使用数组。 当您需要哈希接口时,可以执行以下操作

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

4
我建议您执行以下步骤:
  • 从哈希表中提取键,并找到给定键的索引
  • 如果要在给定键之后而不是之前插入给定对,则将索引加1
  • 将哈希表转换为数组
  • 在计算得出的索引之前(如果索引等于数组大小,则是最后一个对之后),将对插入数组中
  • 将生成的数组转换回哈希表
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"]} 

请注意,这种方法实际上比删除和重新添加元素还要低效:http://ideone.com/HUKp7z - Yam Marcovic
@Yam,这是一个有用的发现。我刚刚注意到我的答案与你(早先)的答案相似。 - Cary Swoveland
虽然在性能不是一个特别关键的情况下(可以认为大多数Ruby应用程序都是如此),这绝对是更优雅的选择。 - Yam Marcovic

2
的答案稍作改进(我想直接评论,但是声望不够)。
如果您希望一次插入多个哈希键(带有多个键的pair),可以使用的变体之一进行修改:

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 可以是一个或多个哈希键,因此这并不会破坏原始用例,只是扩展了它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接