具有以下索引哈希:
{
'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}}