ruby / indexed hash / empty nils

时间:2018-05-31 11:19:46

标签: arrays ruby hash

拥有以下索引哈希:

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

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

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

获得此类结果的最佳方法是什么?

3 个答案:

答案 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)。