5

我有一个Fruit名为 的结构列表basket。每个Fruit结构都有一个name(字符串)和一个calories(整数)。我想这样排序basket

  1. Fruit最高的scalories最先出现。例如,500 卡路里的水果出现在 400 卡路里的水果之前。

  2. 如果两个Fruits 相等calories,则按字母顺序先出现Fruitname先出现,忽略大小写。例如,给定两种热量相同的水果,一种名为“香​​蕉”的水果将排在一种名为“柑橘”的水果之前。

的定义Fruit不是我可以控制的,所以我更喜欢不涉及将任何东西混入Fruit或更改它的解决方案。这可能吗?

4

4 回答 4

12

简单的解决方案是

basket.sort_by { |f| [-f.calories, f.name] }

当然,如果这是水果规范排序顺序,那么它应该使用<=>方法定义,并将Comparable模块混合到Fruit

于 2009-05-12T13:18:40.223 回答
2

假设您的购物篮是一个数组或其子类。

快捷方式

Enumerable.sort_by

正如Gareth指出的,Enumerable(包含在 Array 中)有一个 sort_by 方法,该方法遍历每个列表项一次。一旦你掌握了它的窍门,这将更快地运行和更快地编写。

# -f.calories to sort descending
# name.downcase to do a case-insensitive sort
basket = basket.sort_by { |f| [-f.calories, f.name.downcase] }

Perl 方式

数组排序

来自 Perl 背景,我的第一个冲动是抓住宇宙飞船运算符 <=>。调皮的小恶魔。数组有排序和排序!使其非常有用的方法。此解决方案速度较慢,并且因为它更长,所以更可能引入错误。使用它的唯一原因是,如果您正在与不熟悉 Ruby 并且不愿意在 StackOverflow 上找到正确方法的人打交道。

baseket.sort! { |a,b|
  if a.calories == b.calories
    a.name.downcase <=> b.name.downcase
  else
    # Reverse the result to sort highest first.
    -(a.calories <=> b.calories)
  end
}
于 2009-05-12T13:19:57.740 回答
1

请参阅Array#sortAPI 文档)。您可以传入一个返回 -1、0 或 1 给定两个Fruit对象的块,并且您的块可以使用您喜欢的任何属性来确定这些值。

于 2009-05-12T13:18:12.907 回答
1

如果您需要对 Fruits 进行大量分类,您可能应该在前面多做一些工作并使您的对象具有可比性。

为此,您需要实现 Spaceship-Operator ( <=>) 并包含 Comparable。

class Fruit
  attr_accessor :name, :color

  def <=>(other)
    # use Array#<=> to compare the attributes
    [self.name.downcase, self.color] <=> [other.name.downcase, other.color]
  end

  include Comparable
end

那么你可以简单地做:

list_of_fruits.sort

Comparable 还免费为您提供了许多其他方法(==, <, >),因此您可以执行以下操作 if (apple < banana)(有关更多信息,请参阅Comparable 模块的文档)

<=>, 指定返回-1ifself小于other, +1ifother小于 并且0两个对象相等。

于 2009-05-12T19:57:24.910 回答