是否可以根据单个对象对方法的响应对对象列表进行排序?



我想展示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" }

相关内容

  • 没有找到相关文章

最新更新