【问题标题】:Conditionally extract hashes from array of hashes有条件地从哈希数组中提取哈希
【发布时间】:2015-08-26 21:02:09
【问题描述】:

来自以下哈希数组:

x = [
  {"creationDate"=>123456,"createdBy"=>"test_user1"},
  {"creationDate"=>123459,"createdBy"=>"test_user1"},
  {"creationDate"=>123458,"createdBy"=>"test_user1"},
  {"creationDate"=>123454,"createdBy"=>"test_user2"},
  {"creationDate"=>123452,"createdBy"=>"test_user2"},
  {"creationDate"=>123451,"createdBy"=>"test_user2"}
]

我试图找到最大的:creationDate 值,其中:createdBy 的值是"test_user1"。我这样做了:

x.map {|a| a['creationDate'] if a['createdBy'] == 'test_user1'}
# => [123456,123459,123458,nil,nil,nil]

我想摆脱 nil 以便可以将 max 应用于该数组。如何修改上面的代码?

【问题讨论】:

  • @YuHao:我认为这是新 ruby​​ 中的有效语法
  • 无法复制。投票结束。
  • @SergioTulentsev 确实是有效的语法,但请注意结果无法重现。
  • @sawa:是的,他把例子搞砸了

标签: arrays ruby hash


【解决方案1】:

你想在这里做的是:

x.select { |record| record[:createdBy] == 'test_user1' }.map { |record| record[:creationDate] }.max
  # => 123459

一般来说,要从数组中删除nils,您可以简单地调用Array#compact

[1, nil, nil, 2, 'foo', nil].compact # => [1, 2, "foo"]

【讨论】:

  • 感谢 .compact。这正是我想要的。
【解决方案2】:

这和你打算在 python 中做的很接近:

x.select { |n| n[:createdBy] == "test_user1" }.max_by { |n| n[:creationDate] }

第一个操作选择由“test_user1”创建的记录,而第二个操作根据creationDate获取结果数组的最大值

【讨论】:

  • 这会返回记录(哈希)而不是最大日期本身。
  • @Krule 小心编辑:我重用了与海报相同的约定,并且海报使用基于字符串的哈希而不是基于原子的哈希,所以你的编辑将失败......
  • 它实际上不是基于字符串的哈希。在这种情况下,他将不得不使用=>。此代码将返回 nil: x.select { |n| n["createdBy"] == "test_user1" }.max_by { |n| n["creationDate"] }
  • @krule :你说得对,我认为这是一个打字错误,但我不知道 'key':value 语法,只有 key:value 一个(我认为它创造了更多问题比它解决....)
  • @tomsoft:这种语法很少使用,因为它是在 Ruby 2.2 中引入的。我更喜欢以前的方法(ruby 2、2.1)syntax error, unexpected ':', expecting =>(ruby 1.9)syntax error, unexpected '}', expecting $end。但是由于语言倾向于使字符串不可变(在 ruby​​ 3 中)和对符号的厌恶,我可以理解这个决定。也有很多人犯了这个错误。
【解决方案3】:

我猜是这样的:

x.delete_if {|x| x == nil}

【讨论】:

    【解决方案4】:

    这是 inject 等 map-reduce 函数的理想选择。

    x = [{"creationDate" => 123456,"createdBy" => "test_user1"},
         {"creationDate" => 123459,"createdBy" => "test_user1"},
         {"creationDate" => 123458,"createdBy" => "test_user1"},
         {"creationDate" => 123454,"createdBy" => "test_user2"},
         {"creationDate" => 123452,"createdBy" => "test_user2"},
         {"creationDate" => 123451,"createdBy" => "test_user2"}]
    
    x.inject(nil) do |result, item|
      if item["createdBy"] == "test_user1" && (result.nil? or item["creationDate"] > result)
        item["creationDate"]
      else
        result
      end
    end
    

    这是inject 的可能实现。该块将迭代集合中的每个项目,并始终保持最高值。

    【讨论】:

      【解决方案5】:
      x.min_by{|h| [h[:createdBy], -h[:creationDate]]}[:creationDate]
      # => 123459
      

      [123456, 123459, 123458, nil, nil, nil].compact
      # => [123456, 123459, 123458]
      

      【讨论】:

      • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。
      【解决方案6】:

      这行得通:

      x.map {|a| a['creationDate'] if a['createdBy'] == 'test_user1'}.compact.max
      # => 123459
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-23
        • 2012-02-19
        • 1970-01-01
        • 2017-01-24
        • 1970-01-01
        • 2021-11-03
        • 2011-04-20
        • 1970-01-01
        相关资源
        最近更新 更多