我想展示products
的图库,其中包括待售和非待售的产品。只有我希望待售的products
显示在列表的前面,而非待售的对象将显示在列表末尾。
对我来说,实现这一点的一个简单方法是制作两个列表,然后将它们合并(一个是on_sal?对象列表,另一个是非on_sall?对象列表):
available_products = []
sold_products = []
@products.each do |product|
if product.on_sale?
available_products << product
else
sold_products << product
end
end
但是,对于我现有应用程序的结构,由于我的代码中的一个奇怪之处,这将需要大量的重构(我失去了分页,我宁愿不重构)。如果有一种方法可以通过我的product
模型的返回布尔值的方法on_sale?
对现有的对象列表进行排序,那会更容易。
是否可以更优雅地遍历现有列表,并根据rails中的true或false值对其进行排序我之所以这么问,是因为在这个框架/语言(ruby)中隐藏着太多我不知道的东西,我想知道它们是否在我之前就已经完成了。
当然。理想情况下,我们应该使用sort_by!
:来做这样的事情
@products.sort_by! {|product| product.on_sale?}
或是令人眼花缭乱的
@products.sort_by!(&:on_sale?)
但遗憾的是,<=>
不适用于布尔型(请参阅Ruby中的t排序或宇宙飞船(飞碟)操作员(<=>)为什么不处理布尔型?)并且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
返回一个新集合,这通常是一个更干净、不易出错的解决方案,但sort!
会修改原始集合的内容,您说这是一个要求。
@products.sort_by {|product| product.on_sale? ? 0 : 1}
当我不得不根据布尔值进行排序时,我就是这么做的。
无需排序:
products_grouped = @products.partition(&:on_sale?).flatten(1)
升序和降序可以通过交替更改"false"one_answers"true"来完成
Products.sort_by {|product| product.on_sale? == true ? "false" : "true" }