我有一个名为Fruit
的{{1}}结构列表。每个basket
结构都有Fruit
(字符串)和name
(整数)。我想对calories
进行排序,以便:
首先出现basket
Fruit
calories
。例如,含400卡路里的水果出现在400卡路里的水果之前。
如果两个Fruit
具有相同的calories
,则Fruit
按字母顺序排在第一位name
,忽略大小写。例如,给定两个具有相同卡路里的水果,一个名为“香蕉”的水果将出现在一个名为“柑橘”的水果之前。
Fruit
的定义不是我控制的,所以我更喜欢不涉及将任何内容混合到Fruit
或更改它的解决方案。这可能吗?
答案 0 :(得分:12)
简单的解决方案是
basket.sort_by { |f| [-f.calories, f.name] }
当然,如果这是 水果的规范排序顺序,那么应使用<=>
方法和Comparable
进行定义模块混合到Fruit
答案 1 :(得分:2)
我们假设您的购物篮是一个数组或其子类。
正如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背景,我的第一个冲动就是抓住宇宙飞船运营商&lt; =&gt;。厚脸皮的小恶魔。数组有排序和排序!使它非常有用的方法。这个解决方案速度较慢,因为它的时间越长,就越有可能引入错误。使用它的唯一原因是,如果您正在与不熟悉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
}
答案 2 :(得分:1)
请参阅Array#sort
(API doc)。给定两个Fruit
对象,您可以传入一个返回-1,0或1的块,您的块可以使用您喜欢的任何属性来确定这些值。
答案 3 :(得分:1)
如果你需要经常对Fruit进行分类,你可能应该先做一些工作并使你的对象具有可比性。
为此,您需要实施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)
之类的操作(请参阅the documentation for the Comparable Module了解更多信息)
&lt; =&gt;,如果-1
小于self
则返回other
,+1
如果other
小且{{1}如果两个对象都相等。