是否可以根据单个对象对方法的响应对对象列表进行排序?
我想展示一个产品库,其中包括出售和非出售的产品。 只有我希望待售的products
出现在列表的前面,而非待售的对象才会出现在列表的末尾。
我完成此任务的一个简单方法是创建两个列表,然后合并它们(一个on_sale?对象列表和一个not 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?
方法对现有的对象列表进行排序,那会更容易on_sale?
它返回一个布尔值。
是否可以更优雅地遍历现有列表并通过rails中的true或false值对其进行排序? 我只是问,因为有很多我不知道隐藏在这个框架/语言(ruby)中,我想知道他们是否在我之前完成了工作。
当然。 理想情况下,我们使用sort_by!
做这样的事情sort_by!
:
@products.sort_by! {|product| product.on_sale?}
或者是流氓
@products.sort_by!(&:on_sale?)
但遗憾的是, <=>
不适用于布尔值(请参阅为什么不排序或太空船(飞碟)运算符(<=>)在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之前,因为你想要"false"
之前的"false"
"true"
值)
或者如果您有二级排序:
@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)
上升和下降可以通过相互改变“假”和“真”来完成
Products.sort_by {|product| product.on_sale? == true ? "false" : "true" }