基于Ruby中该键的值的数量合并散列中的键值对的最佳方法

时间:2013-03-22 03:23:27

标签: ruby arrays ruby-on-rails-3 hash key

我在ruby中有一个数组哈希:

 @people = { "a" => ["john", "mark", "tony"], "b"=> ["tom","tim"], 
            "c" =>["jane"], "others"=>["rob", "ryan"] }

我想合并所有键值对,其中数组中少于3个项用于特定键值。它们应该合并到名为“其他”的键中,以大致给出

的结果
 @people = { "a" => ["john", "mark", "tony"], 
           "others"=> ["rob", "ryan", "tom", "tim", "jane"] }

使用以下代码是有问题的,因为散列中的重复键值不能存在:

 @people = Hash[@people.map{|k,v| v.count<3 ? ["others",v] : [k,v]} ] %>

什么是优雅解决这个问题的最好方法?

6 个答案:

答案 0 :(得分:2)

你几乎拥有它,问题是,正如你所注意到的那样,由于重复,你不能动态地构建哈希的键/值对。解决问题的一种方法是从你想要构建的内容开始:

@people = @people.each_with_object({ 'others' => [ ] }) do |(k,v), h|
    if(v.length >= 3)
        h[k] = v
    else
        h['others'] += v
    end
end

或者,如果你不喜欢each_with_object,你可以:

h = { 'others' => [ ] }
@people.each do |k, v|
    # as above
end
@people = h

或者你可以使用inject几乎相同的结构(照常照常从块中返回正确的东西)。

当然还有其他方法可以做到这一点,但这些方法非常清晰易懂; IMO清晰度应该是您的第一个目标。

答案 1 :(得分:1)

尝试:

>> @people = { "a" => ["john", "mark", "tony"], "b"=> ["tom","tim"], 
        "c" =>["jane"], "others"=>["rob", "ryan"] }

>> @new_people = {"others" => []}

>> @people.each_pair {|k,v| (v.size >= 3 && k!="others") ? @new_people.merge!(k=>v) : @new_people['others']+= v}    

>> @new_people
=> {"others"=>["rob", "ryan", "jane", "tom", "tim"], "a"=>["john", "mark", "tony"]}

答案 2 :(得分:1)

Hash[ @people.group_by { |k,v| v.size < 3 ? 'others' : k }.
              map { |k,v| [k, v.flat_map(&:last)] } ]

=> {"a"=>["john", "mark", "tony"],
    "others"=>["tom", "tim", "jane", "rob", "ryan"]}

答案 3 :(得分:0)

这个怎么样:

> less_than_three, others = @people.partition {|(key, values)| values.size >= 3 }
> Hash[less_than_three]
# => {"a"=>["john", "mark", "tony"]}
> Hash["others" => others.map {|o| o.last}.flatten]
# => {"others"=>["tom", "tim", "jane", "rob", "ryan"]}

答案 4 :(得分:0)

@people[:others] = []
@people.each do |k, v|
  @people[:others] |= @people.delete(k) if v.size < 3
end

答案 5 :(得分:0)

@people.inject({}) do |m, (k, v)|
  m[i = v.size >= 3 ? k : 'others'] = m[i].to_a + v
  m
end