如何按升序对ruby数组进行排序,但最后保持为0

时间:2022-08-20 15:58:00

I am trying to sort a Ruby array with the following function

我正在尝试使用以下函数对Ruby数组进行排序

@prices = @item.prices.sort { |x,y| x.total <=> y.total }

Which orders from the lowest to the highest cost. However some products have a total of 0.00 and I want them to appear last rather than at the top.

从最低到最高的订单。然而,有些产品总共只有0.00美元,我希望它们出现在最后而不是顶部。

I have tried a few things but would like some way to modify this block to sort zero at the bottom but keep the rest in ascending order.

我已经尝试了一些东西,但是我想要一些方法来修改这个块,使其在底部为0排序,但将其余的按升序排序。

Thanks.

谢谢。

5 个解决方案

#1


1  

So devise a comparator to do that ...

所以设计一个比较器来做这个…

if x.total == 0
  # always consider 0 "largest" and no 0 can be larger than another
  # (make sure 0.0 is 0 and not a number really close to 0)
  # perhaps x or y should be first for other reasons as well?
  1
else
  # otherwise lower to higher as normal
  x.total <=> y.total
end

Or without comments:

或没有评论:

foo.sort {|x, y| if x.total == 0 then 1 else x.total <=> y.total end}

Happy coding.

快乐的编码。

#2


3  

Try this out, I think it is doing what you request:

试试这个吧,我想它是在做你想做的事情:

@prices = @item.prices.sort {|a,b| a.total==0 ? 1 : b.total==0 ? -1 : a.total<=>b.total}

#3


2  

prices = [0, 1, 2, 0,4, 3]
prices = prices.sort_by do |price|
  [
    if price == 0
      1
    else
      0
    end,
    price
  ]
end
p prices
# => [1, 2, 3, 4, 0, 0]

The trick here is that arrays are compared by comparing their first elements, but if those elements are equal, then by comparing their next elements, and so on. So having the sort_by block yield an array lets you determine primary sort order, secondary sort order, and so on in a clean manner.

这里的诀窍是通过比较它们的第一个元素来比较数组,但是如果这些元素是相等的,那么通过比较它们的下一个元素,等等。因此,让sort_by块产生一个数组,可以让您以一种干净的方式确定主排序顺序、次排序顺序等等。

#4


2  

Just for the record:

只是为了记录:

>> a = [0, 1, 3, 0, 2, 5, 0, 9]
=> [0, 1, 3, 0, 2, 5, 0, 9]
>> a.sort_by { |x| x.zero? ? Float::MAX : x }
=> [1, 2, 3, 5, 9, 0, 0, 0]

On most platforms 1.0/0 will evaluate to Infinity, so you can also use this instead of Float::MAX:

在大多数平台上,1.0/0的值都是无穷大的,所以你也可以用这个来代替Float::MAX:

>> b = [1,4,2,0,5,0]
=> [1, 4, 2, 0, 5, 0]
>> Inf = 1.0/0
=> Infinity
>> b.sort_by { |x| x.zero? ? Inf : x }
=> [1, 2, 4, 5, 0, 0]

#5


0  

This would feel less hacky and less write-only to me:

这会让我觉得不那么陈腐,不那么只写:

prices = prices.sort_by do |price| 
  zero_status = price.zero? ? 1 : 0
  [zero_status, price]
end

because it's an idiomatic way of sorting something by two criteria, which is what you're doing here.

因为这是一种按两个标准排序的习惯方法,这就是你在这里做的。

#1


1  

So devise a comparator to do that ...

所以设计一个比较器来做这个…

if x.total == 0
  # always consider 0 "largest" and no 0 can be larger than another
  # (make sure 0.0 is 0 and not a number really close to 0)
  # perhaps x or y should be first for other reasons as well?
  1
else
  # otherwise lower to higher as normal
  x.total <=> y.total
end

Or without comments:

或没有评论:

foo.sort {|x, y| if x.total == 0 then 1 else x.total <=> y.total end}

Happy coding.

快乐的编码。

#2


3  

Try this out, I think it is doing what you request:

试试这个吧,我想它是在做你想做的事情:

@prices = @item.prices.sort {|a,b| a.total==0 ? 1 : b.total==0 ? -1 : a.total<=>b.total}

#3


2  

prices = [0, 1, 2, 0,4, 3]
prices = prices.sort_by do |price|
  [
    if price == 0
      1
    else
      0
    end,
    price
  ]
end
p prices
# => [1, 2, 3, 4, 0, 0]

The trick here is that arrays are compared by comparing their first elements, but if those elements are equal, then by comparing their next elements, and so on. So having the sort_by block yield an array lets you determine primary sort order, secondary sort order, and so on in a clean manner.

这里的诀窍是通过比较它们的第一个元素来比较数组,但是如果这些元素是相等的,那么通过比较它们的下一个元素,等等。因此,让sort_by块产生一个数组,可以让您以一种干净的方式确定主排序顺序、次排序顺序等等。

#4


2  

Just for the record:

只是为了记录:

>> a = [0, 1, 3, 0, 2, 5, 0, 9]
=> [0, 1, 3, 0, 2, 5, 0, 9]
>> a.sort_by { |x| x.zero? ? Float::MAX : x }
=> [1, 2, 3, 5, 9, 0, 0, 0]

On most platforms 1.0/0 will evaluate to Infinity, so you can also use this instead of Float::MAX:

在大多数平台上,1.0/0的值都是无穷大的,所以你也可以用这个来代替Float::MAX:

>> b = [1,4,2,0,5,0]
=> [1, 4, 2, 0, 5, 0]
>> Inf = 1.0/0
=> Infinity
>> b.sort_by { |x| x.zero? ? Inf : x }
=> [1, 2, 4, 5, 0, 0]

#5


0  

This would feel less hacky and less write-only to me:

这会让我觉得不那么陈腐,不那么只写:

prices = prices.sort_by do |price| 
  zero_status = price.zero? ? 1 : 0
  [zero_status, price]
end

because it's an idiomatic way of sorting something by two criteria, which is what you're doing here.

因为这是一种按两个标准排序的习惯方法,这就是你在这里做的。