我在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]} ] %>
什么是优雅解决这个问题的最好方法?
答案 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