简体   繁体   English

从红宝石的哈希数组中获得独特的属性

[英]Get unique properties from array of hashes in ruby

Given an array of hashes, I want to create a method that returns a hash where the keys are the unique values of the hashes in the array. 给定一个哈希数组,我想创建一个返回哈希值的方法,其中键是数组中哈希值的唯一值。

For example, I'd like to take 例如,我想拿

[
  {foo: 'bar', baz: 'bang'},
  {foo: 'rab', baz: 'bang'},
  {foo: 'bizz', baz: 'buzz'}
]

and return 然后返回

{
  foo: ['bar', 'rab', 'bizz'],
  baz: ['bang', 'buzz']
}

I am currently accomplishing this using: 我目前正在使用以下方法完成此操作:

def my_fantastic_method(data)
  response_data = { foo: [], baz: []}
  data.each { |data| 
    data.attributes.each { |key, value| 
      response_data[key.to_sym] << value 
    } 
  }
  response_data.each { |key, value| response_data[key] = response_data[key].uniq }
  response_data
end

Is there a more elegant way of doing this? 有没有更优雅的方式做到这一点? Thanks! 谢谢!

Your current approach is already pretty good; 您当前的方法已经相当不错了; I don't see much room for improvement. 我认为没有太大的改进空间。 I would write it like this: 我会这样写:

def my_fantastic_method(data_list)
  data_list.each_with_object(Hash.new { |h, k| h[k] = Set.new }) do |data, result| 
    data.attributes.each do |key, value|
      result[key.to_sym] << value
    end
  end
end
  • By setting a default value on each hash value, I have eliminated the need to explicitly declare foo: [], bar: [] . 通过为每个哈希值设置默认值 ,我消除了显式声明foo: [], bar: []
  • By using each_with_object , I have eliminated the need to declare a local variable and explicitly return it at the end. 通过使用each_with_object ,我消除了声明局部变量并在最后显式返回它的需要。
  • By using Set , there is no need to call uniq on the final result. 通过使用Set ,无需对最终结果调用uniq This requires less code, and is more performant. 这需要更少的代码,并且性能更高。 However, if you really want the final result to be a mapping to Array s rather than Set s, then you would need to call to_a on each value at the end of the method. 但是,如果您确实希望最终结果是到Array而不是Set的映射,则需要在方法末尾的每个值上调用to_a
  • I have used different variable names for data_list and data . 我为data_listdata使用了不同的变量名。 Call these whatever you like, but it's typically considered bad practice to shadow outer variables. 随便您如何称呼它们,但是通常不建议使用外部变量。

Here are a couple of one-liners. 这是一对单线。 (I'm pretty sure @eiko was being facetious, but I'm proving him correct) (我很确定@eiko一直在嬉戏,但我证明他是正确的)

This one reads well and is easy to follow (caveat: requires Ruby 2.4+ for transform_values ): 这本书读起来很好,很容易理解(注意: transform_values需要Ruby 2.4+):

array.flat_map(&:entries).group_by(&:first).transform_values{|v| v.map(&:last).uniq}

Here's another, using the block form of merge to specify an alternate merge method, which in this case is combining the values into a uniq array: 这是另一种方法,使用merge的块形式指定替代的合并方法,在这种情况下,该方法将值合并为uniq数组:

array.reduce{|h, el| h.merge(el){|k, old, new| ([old]+[new]).flatten.uniq}}

You already have a pretty good answer, but I felt golfy and so here is a shorter one: 您已经有了一个不错的答案,但是我感到高尔夫球了,所以这里的答案更短:

def the_combiner(a)
  hash = {}
  a.map(&:to_a).flatten(1).each do |k,v|
    hash[k] ||= []
    hash[k].push(v)
  end
  hash
end

Try this: 尝试这个:

array.flat_map(&:entries)
  .group_by(&:first)
  .map{|k,v| {k => v.map(&:last)} }

OR 要么

a.inject({}) {|old_h, new_h|
  new_h.each_pair {|k, v|
    old_h.key?(k) ? old_h[k] << v : old_h[k]=[v]};
    old_h}

If, as in the example, all hashes have the same keys, you could do as follows. 如果像本例中那样,所有散列都具有相同的密钥,则可以执行以下操作。

arr = [{ foo: 'bar', baz: 'bang' },
       { foo: 'rab', baz: 'bang' },
       { foo: 'bizz', baz: 'buzz' }]

keys = arr.first.keys
keys.zip(arr.map { |h| h.values_at(*keys) }.transpose.map(&:uniq)).to_h
  #=> {:foo=>["bar", "rab", "bizz"], :baz=>["bang", "buzz"]}

The steps are as follows. 步骤如下。

keys = arr.first.keys
  #=> [:foo, :baz]
a = arr.map { |h| h.values_at(*keys) }
  #=> [["bar", "bang"], ["rab", "bang"], ["bizz", "buzz"]]
b = a.transpose
  #=> [["bar", "rab", "bizz"], ["bang", "bang", "buzz"]]
c = b.map(&:uniq)
  #=> [["bar", "rab", "bizz"], ["bang", "buzz"]]
d = c.to_h
  #=> <array of hashes shown above>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM