有没有办法检查数组中的哈希是否包含ruby中的类似键值对?

时间:2017-06-25 16:46:06

标签: ruby

例如,我有

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个哈希值。

3 个答案:

答案 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] } }

如果我们有两个值xykey[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 } }