红宝石/索引哈希/空零



具有以下索引哈希:

{
'1' => { a: :b },
'2' => { c: :d },
'3' => nil,
'4' => { e: :f }
}

我会考虑在删除空键的同时"重置"索引键; 换句话说,产生以下内容:

{
'1' => { a: :b },
'2' => { c: :d },
'3' => { e: :f }
}

获得这种结果的最佳方法是什么?

只需筛选值并分配新键。

hash.
values.
reject(&:nil?). # or `compact`, credits to @KimmoLehto
map.
with_index(1) { |v, i| [i.to_s, v] }.
to_h
#⇒ {"1"=>{:a=>:b}, "2"=>{:c=>:d}, "3"=>{:e=>:f}}

另请参阅@Stefan的宝贵评论,以获取使用Hash#transform_keys的更简洁的2.5+版本。

h = { '1' => { a: :b }, '2' => { c: :d }, '3' => nil, '4' => { e: :f } }
s = '0'
h.each_with_object({}) { |(_,v),g| g[s = s.succ] = v unless v.nil? }
#=> {"1"=>{:a=>:b}, "2"=>{:c=>:d}, "3"=>{:e=>:f}}. 

请参阅字符串#succ(又名String#next(。

我使用Enumerable#reduce。 在这种情况下,reduce以空哈希(reduce({})(开头作为acc的初始值。然后它遍历hash并为每个键值对调用给定的块(el作为数组 [键,值](。每个块的最后一个值将是下一次迭代的acc

如果hash中的键值对的值是哈希,那么我将acc中的键数增加 1 以获得下一个键并将其与值一起放入 acc 中。因此,我在每次迭代时都以acc完成结果。

hash.reduce({}){ |acc, el| 
acc.merge(el.last.is_a?(Hash) ? {(acc.keys.count + 1).to_s => el.last} : {})
}
# => {"1"=>{:a=>:b}, "2"=>{:c=>:d}, "3"=>{:e=>:f}}

更多解释性:

hash.reduce({}) do |acc, el| 
hash_to_merge_into_acc = {}
if el.last.is_a?(Hash)
new_key = (acc.keys.count + 1).to_s
hash_to_merge_into_acc[new_key] = el.last
end
acc.merge(hash_to_merge_into_acc)
end
# => {"1"=>{:a=>:b}, "2"=>{:c=>:d}, "3"=>{:e=>:f}}

最新更新