根据单个对象对某个方法的响应,是否可以对对象列表进行排序?
我想展示一个products
的画廊,其中包含既可供出售又可出售的产品。我只希望待售的products
出现在列表的前面,而不出售的对象将出现在列表的末尾。根据单个对象对某个方法的响应,是否可以对对象列表进行排序?
对我来说,做到这一点的一个简单方法是使两个列表,然后将它们合并(on_sale对象的一个列表,而不是on_sale对象的一个列表?):
available_products = []
sold_products = []
@products.each do |product|
if product.on_sale?
available_products << product
else
sold_products << product
end
end
。 。 。但是,对我现有的应用程序的结构,这将需要过多的重构,由于我的代码中的怪异(我失去了我的分页,我宁愿不重构)。如果有方法通过我的product
模型的方法on_sale?
(它返回一个布尔值)对现有对象列表进行排序,将会更容易。
是否有可能更优雅地遍历现有的列表,并通过这个真正的或错误的值在轨道排序它?我只问,因为有太多我不知道隐藏在这个框架/语言(红宝石),我想知道他们的工作是否已经完成在我面前。
当然。理想情况下,我们会使用sort_by!
做这样的事情:
@products.sort_by! {|product| product.on_sale?}
或snazzier
@products.sort_by!(&:on_sale?)
但可悲的是,<=>
不会为布尔工作(见Why doesn't sort or the spaceship (flying saucer) operator (<=>) work on booleans in Ruby?)和sort_by
布尔不起作用值,所以我们需要用这一招(感谢rohit89!)
@products.sort_by! {|product| product.on_sale? ? 0 : 1}
如果您想要更有趣,sort
方法需要一个块,并且在该块内您可以使用任何您喜欢的逻辑,包括类型转换和多个键。尝试是这样的:
@products.sort! do |a,b|
a_value = a.on_sale? ? 0 : 1
b_value = b.on_sale? ? 0 : 1
a_value <=> b_value
end
或本:
@products.sort! do |a,b|
b.on_sale?.to_s <=> a.on_sale?.to_s
end
(把B A,因为你要"true"
值来"false"
前前)
,或者如果你有一个辅助排序:
@products.sort! do |a,b|
if a.on_sale? != b.on_sale?
b.on_sale?.to_s <=> a.on_sale?.to_s
else
a.name <=> b.name
end
end
请注意,sort
返回一个ew collection,这通常是一个更干净,更不容易出错的解决方案,但sort!
会修改原始集合的内容,这是您的要求。
@products.sort_by {|product| product.on_sale? ? 0 : 1}
这是我做过什么,当我不得不基于布尔值排序。
无需排序:
products_grouped = @products.partition(&:on_sale?).flatten(1)
上升和下降可以通过改变间做 “假” 与 “真”
Products.sort_by {|product| product.on_sale? == true ? "false" : "true" }
看起来不错!但是我用我的特定代码遇到了问题,也许你可以帮助我。如果我使用单行命令,我会得到以下错误:“FalseClass与true failed的比较”,如果我使用您提到的第一个代码,则会得到[MyModule] :: Product与[MyModule] :: Product的比较失败'。不知道为什么这会失败。 – Ecnalyr 2013-02-11 15:26:22
一些注意事项:1)应尽可能使用'sort_by'而不是'sort'(更具说明性,更简洁,更高效)。可以在上面显示的所有代码片段中使用它。 2)我最好链接到非破坏性的'Enumerable#sort_by',只要有可能就应该避免就地更新。 3)'@ product.sort_by(&:on_sale?)'。 – tokland 2013-02-11 15:28:50
看起来像''不适用于布尔值(ruby-1.9.3-p327)。现在看看它...是的,http://grosser.it/2010/07/30/ruby-true-false-comparison-with/确认它为较早的版本 – AlexChaffee 2013-02-11 15:39:56