按照数字(从高到低)和字母(按字母表顺序)对一组对象进行排序。

5
我正在构建一个小部件,用于显示奥运会的奖牌计数。我有一组“国家”对象,每个对象都有一个“名称”属性和“金牌”,“银牌”和“铜牌”的奖牌计数。
列表应按以下方式排序: 1.首先按总奖牌数排序 2.如果奖牌数量相同,则按类型排序(金牌>银牌>铜牌,即两枚金牌> 1枚金牌+ 1枚银牌) 3.如果奖牌数量和类型相同,则按字母顺序排序
我在ruby中执行此操作,但我想这种方法肯定还有更加优雅的解决方案。
这是我所做的:
1.创建具有加权奖牌总数的虚拟属性。因此,如果他们有2个金牌和1个银牌,则加权总数为“3.020100”。1个金牌,1个银牌和1个铜牌将是“3.010101” 2.由于我们希望按最高奖牌数首先排序,因此列表按降序排序。但是然后我们希望在此之后按字母顺序进行子排序(即ASC)。因此,我创建了一个函数,可以alpha-invert单词(即“canada”=>“xzmzwz”) 3.将加权总数转换为字符串,连接反转的名称(即“3010101xzmzwz”),然后按降序排序。大功告成。
到现在为止,有人已经想出了如何用约2行代码完成相同的操作。你能否给我指点一下呢?
3个回答

10
countries.sort_by do |country|
  medals = country.gold + country.silver + country.bronze
  [-medals, -country.gold, -country.silver, country.name]
end

这是特定于某个Ruby版本吗?对我来说似乎不起作用。 - Beanish
不应该出现这种情况。在1.8.7和1.9上,它可以正常工作,我没有看到任何理由它不能在1.8.6上运行。sort_by在1.8.6中确实存在,Array#<=>也是如此。 - sepp2k
请注意,sort_by 不会就地排序。 - sepp2k

1
一个简单的方法是使用sort_by和一些任意格式的字符串,例如:
countries.sort_by do |c|
  "%010d-%010d-%010d-%s" % [ c.gold, c.silver, c.bronze, c.name ]
end

这将通过填充赢得奖牌数量到可预期的10个位数,将所有国家转换为ASCII可排序列表。如果有人赢得超过十亿枚奖牌,您的程序可能会发生故障,但这似乎是一个合理的限制。


+1 个“合理的限制” :-) 然而,请注意,由于完全超出您控制范围的情况,合理的限制有时可能变得不合理:http://Blog.BusinessOfSoftware.Org/2009/01/bos-digest---when-good-assumptions-go-bad.html - Jörg W Mittag
只有在津巴布韦,您才需要使用大数(Bignum)来表示您的银行账户余额。 - tadman
我不相信这解决了我的一个最初的要求——奖牌计数应该按降序排序(最大的在前),但字母表子排序应该按升序排序(最小的,或a..z)。因此,按“<金牌>-<银牌>-<铜牌>-<名称>”排序将首先排序奖牌数量最少的国家。对于奖牌数量相同的国家,先按最大奖牌数排序,然后按字母表子排序。 - dlehman
可以通过反转数字计数来轻松翻转它,但与早期解决方案相比,这将进入深度黑客领域。"%010d-%010d-%010d-%s" % [ 10_000_000_000 - c.gold, 10_000_000_000 - c.silver, 10_000_000_000 - c.bronze, c.name ] - tadman

0
在Java中,您可以在对象上实现可比较接口,然后它可以轻松地在ArrayList或Array中进行排序。在Ruby中是否有一种机制来告诉如何比较两个“Country”对象?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接