基于某些元素中可能为零的属性对数组进行排序

min*_*eow 18 ruby arrays sorting heterogeneous-array

我有一个对象数组

[<#a star=1  val=1>, <#a star=nil val=3> , <#a star=2  val=2>]
Run Code Online (Sandbox Code Playgroud)

我需要按时间排序数组,然后按val排序

[ <#a star=2  val=2>, <#a star=1  val=1>, <#a star=nil val=3> ]
Run Code Online (Sandbox Code Playgroud)

但是使用sort_by会抛出错误,因为时间是零.

我现在用一种丑陋的方式来排序,但我确信有一个很好的方法可以解决它

starred=[]
@answers.each {|a| (starred << a) if a.starred }
@answers=@answers-starred
starred=starred.sort_by {|a| a.starred }.reverse
@answers=starred+@answers
Run Code Online (Sandbox Code Playgroud)

Nak*_*lon 32

starred.sort_by { |a| [a ? 1 : 0, a] }
Run Code Online (Sandbox Code Playgroud)

当必须比较两个元素时,它会比较一个数组.当Ruby比较数组(调用===方法)时,它会比较第一个元素,并且仅当第一个元素相等时才转到第二个元素.? 1 : 0保证,我们将Fixnum作为第一个元素,所以它应该没有错误.

如果你这样做? 0 : 1,nil将出现在数组的末尾而不是开始.
这是一个例子:

irb> [2, 5, 1, nil, 7, 3, nil, nil, 4, 6].sort_by { |i| [i ? 1 : 0, i] }
=> [nil, nil, nil, 1, 2, 3, 4, 5, 6, 7]

irb> [2, 5, 1, nil, 7, 3, nil, nil, 4, 6].sort_by { |i| [i ? 0 : 1, i] }
=> [1, 2, 3, 4, 5, 6, 7, nil, nil, nil]
Run Code Online (Sandbox Code Playgroud)


Ami*_*ana 7

如果你想让nils首先出现(零等价):

@answers.sort_by { |a| a.star or 0 }

如果你想让它们显示在最后,你可以用Max Int替换零,但这感觉太hacky.这可能更好:

@answers.select(&:starred?).sort_by(&:star) + @answers.reject(&:starred?)

Nakilon提供的答案非常棒,尽管你基本上在两个不同的属性上进行了两次排序.在大多数情况下,这可能就足够了.

  • 谢谢@ amin-ariana,您的解决方案对我有用,我认为更具可读性. (3认同)