【问题标题】:How to find max value grouped by multiple keys in array of hashes?如何在哈希数组中找到由多个键分组的最大值?
【发布时间】:2012-05-16 15:25:55
【问题描述】:

拥有具有这种结构的数据。将按“c”升序排列。

[ { 'a' => 1, 'b' => 1, 'c' =>  1, 'd' => '?' },
  { 'a' => 1, 'b' => 1, 'c' =>  2, 'd' => '?' },
  { 'a' => 1, 'b' => 1, 'c' =>  3, 'd' => '?' },
  { 'a' => 1, 'b' => 2, 'c' =>  4, 'd' => '?' },
  { 'a' => 1, 'b' => 2, 'c' =>  5, 'd' => '?' },
  { 'a' => 2, 'b' => 1, 'c' =>  6, 'd' => '?' },
  { 'a' => 2, 'b' => 1, 'c' =>  7, 'd' => '?' },
  { 'a' => 2, 'b' => 1, 'c' =>  8, 'd' => '?' },
  { 'a' => 2, 'b' => 2, 'c' =>  9, 'd' => '?' },
  { 'a' => 2, 'b' => 2, 'c' => 10, 'd' => '?' } ]

想要由 'a' 和 'b' 的每个唯一组合分组的 'c' 的最大值数组。

[ { 'a' => 1, 'b' => 1, 'c' =>  3, 'd' => '?' },
  { 'a' => 1, 'b' => 2, 'c' =>  5, 'd' => '?' },
  { 'a' => 2, 'b' => 1, 'c' =>  8, 'd' => '?' },
  { 'a' => 2, 'b' => 2, 'c' => 10, 'd' => '?' } ]

其他键需要保留,但与转换无关。到目前为止,我能想到的最好的办法是反转数组(因此按“c”降序排列),uniq 按“a”和“b”,然后再次反转数组。但我依赖于 uniq_by 的实现,总是返回找到的第一个唯一项目。规范没有这么说,所以我担心依赖这种行为,因为它可能会在未来的版本中改变。还想知道这是否是一种非常低效的方法。

@data.reverse!.uniq!{|record| [record['a'],record['b']]}.reverse!

有没有更好更有效的方法来做到这一点?如果您确实有更好的方法,请您解释一下,而不是只给我一个我可能无法破译的超级讨厌的单行字。

【问题讨论】:

    标签: ruby arrays hash max uniq


    【解决方案1】:

    其实很简单:

    a.group_by { |h| h.values_at("a", "b") }.map { |_, v| v.max_by { |h| h["c"] } } 
    

    或者使用更好的格式:

    a.group_by do |h|
      h.values_at("a", "b") 
    end.map do |_, v| 
      v.max_by { |h| h["c"] }
    end
    

    解释:首先我们使用Enumerable#group_by 创建一个Hash,并以"a""b"(用Hash#values_at 提取)的组合作为键,并以该组合作为值的所有哈希。然后我们映射这个散列,忽略键并从Enumerable#max_by 的数组中选择具有最大值"c" 的元素。

    【讨论】:

    • 块参数中_的含义能否解释或参考一下?
    • @Flexoid:没有特别的含义,这是一个我不关心的参数,在很多语言中,习惯上在名称中使用下划线来表示。
    • @steenslag 不知何故,"c" 变成了v,我花了一秒钟才弄清楚我在哪里愚蠢;-) 重读我的文字描述很有帮助,因为我描述得当.. .
    • +1 是一个非常惯用的解决方案,尤其是使用values_at(我不会这样做)。虽然我确实更喜欢@steenslag 的.last 而不是_,v desplat。或者更好的是,a.group_by{...}.values.map{...}
    • _ 确实有特殊含义,或者在某些情况下至少 gets special treatment,使用 _ 作为 I don't care 参数的约定很难解释器中的有线支持。不过,这只是在挑选评论:)
    猜你喜欢
    • 2018-04-07
    • 2011-08-27
    • 1970-01-01
    • 2018-03-14
    • 1970-01-01
    • 2016-12-03
    • 2012-10-11
    • 2017-06-20
    • 1970-01-01
    相关资源
    最近更新 更多