拥有以下索引哈希:
{
'1' => { a: :b },
'2' => { c: :d },
'3' => nil,
'4' => { e: :f }
}
我会考虑“重置”索引键,同时删除空键;换句话说,产生以下内容:
{
'1' => { a: :b },
'2' => { c: :d },
'3' => { e: :f }
}
获得此类结果的最佳方法是什么?
答案 0 :(得分:4)
只需过滤值并指定新密钥。
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+版本的重要评论。
答案 1 :(得分:1)
我使用Enumerable#reduce。在这种情况下,reduce
以空哈希(reduce({})
)作为acc
的初始值开头。然后,它遍历hash
并为每个键值对调用给定的块(在el
中作为Array [键,值])。每个块的最后一个值将是下一次迭代的acc
。
如果hash
中键值对的值是Hash,那么我将acc
中的键数增加1以获取下一个键并将其放入符合价值。所以我在每次迭代时都会在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}}
答案 2 :(得分:1)
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}}.
请参阅String#succ(又名String#next
)。