你为你想要做的事情提供了两个选项:
- 获取转换中删除的值的列表
- 通过向键添加特殊字符使键唯一
我认为第二种方法是一个坏主意,原因有两个:a)您必须有一种修改密钥的方法,以允许它们有多个重复的可能性; b) 在原件和复制件之间建立联系会很尴尬。此外,它会很丑陋。
我看到其他人提出了第三种可能性:更改结果哈希的形式,以便为字符串数组赋值。这可能对你有好处,但这不是你所要求的,所以我选择建立一个被删除的值的列表;即,除了第一个。
代码
def create_hash_and_save_extras(arr)
arr.each_slice(2).with_object([{},[]]) { |(k,v),(h,ex)|
h.update({k=>v}) { |k, ov, nv| ex << {k=>nv}; ov } }
end
示例
create_hash_and_save_extras(arr)
#=> [{"19d97e408ee3f993745b053e281ac9dc69519e06"=>"refs/heads/auto",
# "8f6f47c6e8023540b022586e368c68e1e814ce6d"=>"refs/heads/callout_hooks",
# "3cbdb4b2fcb85bc7f0ed08b62e2bf2445a7659e8"=>"refs/heads/elab",
# "d38a9a26ef887c08b306bdab210b39882f58e587"=>"refs/heads/elab_6.1",
# "906dfe6eebff832baf0f92683d751432fcc98ab7"=>"refs/heads/regression"},
# [{"19d97e408ee3f993745b053e281ac9dc69519e06"=>"refs/heads/master"}]]
说明
Enumerable#each_slice 发送到arr 返回一个枚举器:
enum1 = arr.each_slice(2)
#=> #<Enumerator: [
# "19d97e408ee3f993745b053e281ac9dc69519e06", "refs/heads/auto",
# "8f6f47c6e8023540b022586e368c68e1e814ce6d", "refs/heads/callout_hooks",
# ...
# "906dfe6eebff832baf0f92683d751432fcc98ab7", "refs/heads/regression"
# ]:each_slice(2)>
Enumerator#with_object 创建一个由初始空散列(由块变量 h 表示)和一个由块变量 ex 表示的初始空数组(用于“附加”)组成的数组,其中然后发送到enum1 以创建另一个枚举器(您可以将其视为“复合枚举器”——注意下面对each_slice(2)>:with_object({}) 的引用)。
enum2 = enum1.with_object([{},[]])
#=> #<Enumerator: #<Enumerator: [
# "19d97e408ee3f993745b053e281ac9dc69519e06", "refs/heads/auto",
# "8f6f47c6e8023540b022586e368c68e1e814ce6d", "refs/heads/callout_hooks",
# ...
# "906dfe6eebff832baf0f92683d751432fcc98ab7", "refs/heads/regression"
# ]:each_slice(2)>:with_object([{},[])>
我们可以将enum2 转换为一个数组,看看它将传递给它的块:
enum2.to_a
#=> [[["19d97e408ee3f993745b053e281ac9dc69519e06", "refs/heads/auto"],
# [{}, []]],
# [["8f6f47c6e8023540b022586e368c68e1e814ce6d", "refs/heads/callout_hooks"],
# [{}, []]],
# [["3cbdb4b2fcb85bc7f0ed08b62e2bf2445a7659e8", "refs/heads/elab"],
# [{}, []]],
# [["d38a9a26ef887c08b306bdab210b39882f58e587", "refs/heads/elab_6.1"],
# [{}, []]],
# [["19d97e408ee3f993745b053e281ac9dc69519e06", "refs/heads/master"],
# [{}, []]],
# [["906dfe6eebff832baf0f92683d751432fcc98ab7", "refs/heads/regression"],
# [{}, []]],
enum2 传入其块的第一个元素是
[["19d97e408ee3f993745b053e281ac9dc69519e06", "refs/heads/auto"], [{}, []]]]]
因此,块变量分配如下:
k => "19d97e408ee3f993745b053e281ac9dc69519e06"
v => "refs/heads/auto"
h => {}
ex = []
我们现在使用Hash#update(又名Hash#merge!)将{k,v}合并到h(h最初为空。)因此
h.update({k=>v}) { |k, ov, nv| extras << {k=>nv}; ov }
变成
h.update({"19d97e408ee3f993745b053e281ac9dc69519e06"=>"refs/heads/auto"})
紧随其后
{ |k, ov, nv| ex << {k=>nv}; ov }
但该块仅适用于哈希合并哈希 (h) 和正在合并的哈希 (update 的参数) 共享相同的密钥 k,在这种情况下 ov 和 nv 是分别与 h 的这些键关联的值和要合并的哈希值。键 k 的合并值将是块返回的值。是的,这将在我们遇到重复项时适用。
那么现在
h #=> {"19d97e408ee3f993745b053e281ac9dc69519e06"=>"refs/heads/auto"}
我们继续以这种方式处理enum2 的其他每个元素。当我们遇到
k = "19d97e408ee3f993745b053e281ac9dc69519e06"
v = "refs/heads/master"
h = {"19d97e408ee3f993745b053e281ac9dc69519e06"=>"refs/heads/auto",
"8f6f47c6e8023540b022586e368c68e1e814ce6d"=>"refs/heads/callout_hooks",
"3cbdb4b2fcb85bc7f0ed08b62e2bf2445a7659e8"=>"refs/heads/elab",
"d38a9a26ef887c08b306bdab210b39882f58e587"=>"refs/heads/elab_6.1"}
我们发现k已经在合并哈希h中,因此对该块进行评估以确定合并哈希h中k的值。我们希望保留当前值h[k],即ov,这就是块返回的值。然而,首先,我们在(仍然为空的)数组ex 中附加重复值,以哈希表示。
ex << {"19d97e408ee3f993745b053e281ac9dc69519e06" => "refs/heads/master"}