例如,我有
array = [ {name: 'robert', nationality: 'asian', age: 10},
{name: 'robert', nationality: 'asian', age: 5},
{name: 'sira', nationality: 'african', age: 15} ]
我希望得到结果
array = [ {name: 'robert', nationality: 'asian', age: 15},
{name: 'sira', nationality: 'african', age: 15} ]
因为有两个罗伯特具有相同的国籍。
非常感谢任何帮助。
我已尝试Array.uniq! {|e| e[:name] && e[:nationality] }
但我想在两个哈希中添加两个数字 10 + 5
P.S:数组可以有n个哈希值。
答案 0 :(得分:3)
我会从这样的事情开始:
array = [
{ name: 'robert', nationality: 'asian', age: 10 },
{ name: 'robert', nationality: 'asian', age: 5 },
{ name: 'sira', nationality: 'african', age: 15 }
]
array.group_by { |e| e.values_at(:name, :nationality) }
.map { |_, vs| vs.first.merge(age: vs.sum { |v| v[:age] }) }
#=> [
# {
# :name => "robert",
# :nationality => "asian",
# :age => 15
# }, {
# :name => "sira",
# :nationality => "african",
# :age => 15
# }
# ]
答案 1 :(得分:3)
让我们来看看你想要完成什么并从那里开始。您有一些对象的列表,如果它们具有相同的种族和名称,您希望将某些对象合并在一起。所以我们有一个密钥,我们将合并。让我们把它放在编程术语中。
key = proc { |x| [x[:name], x[:nationality]] }
我们已经定义了一个过程,该过程采用哈希并返回其“键”值。如果此过程为两个哈希值返回相同的值(根据eql?
),那么这两个哈希值需要合并在一起。现在,“合并”是什么意思?你想把年龄加在一起,所以让我们写一个合并函数。
merge = proc { |x, y| x.dup.tap { |x1| x1[:age] += y[:age] } }
如果我们有两个值x
和y
,key[x]
和key[y]
相同,我们希望通过制作{{1}的副本来合并它们并添加x
的年龄。这正是这个程序的作用。现在我们有了构建块,我们可以编写算法。
我们希望在使用我们编写的关键过程合并后,在最后生成一个数组。幸运的是,Ruby有一个方便的函数y
,它将为我们做一些非常好的事情。方法each_with_object
将为数组的每个元素执行其块,传递预定值作为另一个参数。这将在这里派上用场。
each_with_object
由于我们使用键和值来进行合并,因此最有效的方法是使用哈希。因此,我们传入一个空哈希作为额外的对象,我们将修改它以累积合并结果。最后,我们不再关心键,因此我们编写result = array.each_with_object({}) do |x, hsh|
# ...
end.values
来获取对象本身。现在是最后的作品。
.values
让我们打破这个。如果哈希已包含if hsh.include? key[x]
hsh[ key[x] ] = merge.call hsh[ key[x] ], x
else
hsh[ key[x] ] = x
end
,这是我们正在查看的对象key[x]
的关键字,那么我们希望将x
与当前为{{1}的值合并}}。这是我们将年龄加在一起的地方。这种方法只有在x
函数是数学家称之为半群的情况下才有效,这是一种说明操作是关联的奇特方式。你不需要太担心;加法是半群的一个很好的例子,所以它可以在这里工作。
无论如何,如果哈希中不存在密钥,我们希望将当前值放在密钥位置的哈希中。返回合并产生的哈希值,然后我们可以从中获取值以获得您想要的结果。
key[x]
现在,我的复杂性理论有点生疏,但是如果Ruby有效地实现了它的哈希类型(我相当确定它),那么这个合并算法是merge
,这意味着它需要线性给定问题大小作为输入,完成时间。
答案 2 :(得分:2)
array.each_with_object(Hash.new(0)) { |g,h| h[[g[:name], g[:nationality]]] += g[:age] }.
map { |(name, nationality),age| { name:name, nationality:nationality, age:age } }
[{ :name=>"robert", :nationality=>"asian", :age=>15 },
{ :name=>"sira", :nationality=>"african", :age=>15 }]
这两个步骤如下。
a = array.each_with_object(Hash.new(0)) { |g,h| h[[g[:name], g[:nationality]]] += g[:age] }
#=> { ["robert", "asian"]=>15, ["sira", "african"]=>15 }
这使用类方法Hash::new创建一个默认值为零的哈希(由块变量h
表示)。一旦这个哈希heen获得它,构造所需的哈希是一件简单的事情:
a.map { |(name, nationality),age| { name:name, nationality:nationality, age:age } }