【问题标题】:How do you sort multiple types in ruby?如何在 ruby​​ 中对多种类型进行排序?
【发布时间】:2011-10-21 13:21:59
【问题描述】:

假设你有一个跑步者数组:

runners = [al, betty, chris, debby]

你有一个方法time 可以返回跑步者在比赛中的时间。

如果time 方法总是返回一个浮点数,我知道您可以使用sort_by 对跑步者进行排序,如下所示:

runners.sort_by do |runner|
    runner.time
end

但是,假设time 有时会返回一个字符串,例如"disqualified"。在那种情况下,你将如何按时间对跑步者进行排序,不合格的跑步者排在最后?如果您希望被取消资格的跑步者首先或其他位置怎么办?

【问题讨论】:

  • 我建议您不要用字符串超载您的预期时间值。相反,请使用单独的 is_disqualified? true/false 属性并让时间值始终是浮点数,或者更好的时间对象。当我们使用意想不到的类型时,逻辑可能会变得非常复杂,当您必须重新访问代码并重新了解为什么以某种方式做事时,这将造成更大的损失。
  • @the Tin Man:这不是Java,函数名应该是disqualified?,而不是is_disqualified?。 :-)
  • 实际上,我是用 ActiveRecord 的术语来思考的。
  • @the Tin Man:我认为 ActiveRecord 也没有在布尔 getter 前使用 is_ 的先例。
  • 我投票取消这个问题的资格,因为它可能与Sort a collection of objects by number (highest first) then by letter (alphabetical) 重复(也是运动主题!)。

标签: ruby sorting


【解决方案1】:

您可以为此创建一个自定义类:

class RunningTime
  attr_reader :time

  def initialize time
    @time = time
  end

  def disqualified?
    @time == 'disqualified'
  end

  def <=> rhs
    case [disqualified?, rhs.disqualified?]
    when [false, true]
      -1
    when [true, true]
      0
    when [true, false]
      1
    else
      time <=> rhs.time
    end
  end
end

runners.sort_by {|runner| RunningTime.new(runner.time)}

【讨论】:

  • 为了理解这门课,我需要做一点学习。感谢您帮助我学习!
  • @Michael:你应该完全忘记我的答案,直接选择 Peter 的答案。 :-P 它与我的答案或多或少有相似的想法,只是简单了 10 倍。
【解决方案2】:

时间回来了Object.time.to_f?如果是这样,对字符串调用 to_f 将返回 0.0。如果没有,请尝试在块中调用 runner.time.to_f。 String 类型的所有时间值都是 0.0。

【讨论】:

  • 问题在于 0 是一个有效的运行时间值,不应被视为不合格。 (问题的更普遍的变体是disqualified 无法映射到 任何 有效数值(包括无穷大)的情况,必须进行特殊处理。这就是我的答案所针对的。)
【解决方案3】:

你可以这样做:

[5,4,"disqualified",2,7].sort_by { |x| x.kind_of?(String) ? Float::INFINITY : x } 
#=> [2, 4, 5, 7, "disqualified"]

在 Ruby Float::INFINITY,但你可以通过Inf = 1.0 / 0 得到它。

【讨论】:

  • @Michael Hoffman:Float::INFINITY 是一个常数,代表一个无限大的浮点数。 IOW:被取消资格的跑步者只会被比作他跑得无限慢。
  • @Jörg W Mittag:感谢您的解释。那么Float指的是float类,而INFINITY是那个类的类常量?
【解决方案4】:

这是一个简单的方法。只需在一个数组中有两个排序字段,Ruby 将按第一个条件排序,然后是第二个条件。

runners.sort_by do |runner|
    [(runner.time == 'disqualified') ? 1 : 0, runner.time]
end

此处1 将排在0 之后,因此不合格的时间将排在最后。

【讨论】:

    【解决方案5】:

    假设您是来自数据库的跑步者,使用单独的字段/方法来检查不合格的跑步者可以让您将排序逻辑推送到数据库层,这比将所有记录加载到内存和排序更快他们在红宝石中。

    【讨论】:

    • 对于我面临的实际问题,我已经采用了您所描述的解决方案(我认为是)。我删除了具有非数字值的项目,对具有非数字值的项目进行了排序,然后在单独的过程中添加了已删除的项目。
    猜你喜欢
    • 1970-01-01
    • 2019-01-18
    • 2020-12-05
    • 2018-09-02
    • 2020-01-21
    • 1970-01-01
    • 2011-12-09
    • 1970-01-01
    • 2021-08-26
    相关资源
    最近更新 更多