Ecn*_*lyr 11 ruby sorting activerecord ruby-on-rails-3 ruby-on-rails-3.2
我想展示一个画廊,products其中包括既可以出售也可以出售的产品.只有我希望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?这会返回一个布尔值.
是否可以更优雅地遍历现有列表并通过rails中的true或false值对其进行排序? 我只是问,因为有很多我不知道隐藏在这个框架/语言(ruby)中,我想知道他们是否在我之前完成了工作.
Ale*_*fee 14
当然.理想情况下,我们会使用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之前因为你想要"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_grouped = @products.partition(&:on_sale?).flatten(1)
| 归档时间: | 
 | 
| 查看次数: | 2072 次 | 
| 最近记录: |