我有一个数组
arr = [["cat", "15"], ["dog", "17"], ["cat", "20"], ["cat", "356"], ["dog", "89"], ["bird", "65"], ["dog", "336"], ["bird", "545"]]
我想按相同的第一项对子数组进行分组,我只需要得到这样的东西:
arr = [["cat", "15", "20", "356"], ["dog", "17", "89", "336"], ["bird", "65","545"]]
谁能帮忙?
下次,如果您添加一些尝试执行的步骤来获得所需的内容,那就太好了,这是一个快速的解决方案:
> arr.group_by(&:shift).map(&:flatten)
#=> [["cat", "15", "20", "356"], ["dog", "17", "89", "336"], ["bird", "65", "545"]]
但是,这会改变原始arr
@Md.法汉记忆有很好的解决方案,没有突变
替代解决方案,不更改原始对象,不需要 dup。
arr.group_by(&:first).map{ |k, v| [k] + v.map { |e| e[1] } }
#=> [["cat", "15", "20", "356"], ["dog", "17", "89", "336"], ["bird", "65", "545"]]
或
arr.group_by(&:first).map{ |k, v| [k] + v.map(&:last) }
#=> [["cat", "15", "20", "356"], ["dog", "17", "89", "336"], ["bird", "65", "545"]]
其他答案已经提供了完美的解决方案。我发布这个是为了展示一个应用程序(鲜为人知? assoc
方法。它扫描数组以查找具有给定第一个元素的子数组,几乎就像数组是哈希一样。这可用于填充结果array
:
result = []
arr.each do |name, value|
group = result.assoc(name)
if group
group << value
else
result << [name, value]
end
end
result
#=> [["cat", "15", "20", "356"], ["dog", "17", "89", "336"], ["bird", "65", "545"]]
代码可以进一步缩短为:
arr.each_with_object([]) do |(name, value), result|
group = result.assoc(name)
group ? group << value : result << [name, value]
end
#=> [["cat", "15", "20", "356"], ["dog", "17", "89", "336"], ["bird", "65", "545"]]
assoc
还可用于轻松地从result
数组中检索特定"键"的值:
name, *values = result.assoc('cat')
name #=> "cat"
values #=> ["15", "20", "356"]
另一种方法是在哈希中添加所有值:
animals = arr.each_with_object(Hash.new{|h, k| h[k] = []}) do |(animal_name, value), obj|
obj[animal_name] << value
end
#=> {"cat"=>["15", "20", "356"], "dog"=>["17", "89", "336"], "bird"=>["65", "545"]}
然后将其转换为预期的输出:
animals.map(&:flatten)
#=> [["cat", "15", "20", "356"], ["dog", "17", "89", "336"], ["bird", "65", "545"]]