Подтвердить что ты не робот

Сортировка массива на основе атрибута, который может быть равен нулю в некоторых элементах

У меня есть массив объектов

[<#a star=1  val=1>, <#a star=nil val=3> , <#a star=2  val=2>]

Мне нужен массив, который будет сортироваться по времени, а затем val

[ <#a star=2  val=2>, <#a star=1  val=1>, <#a star=nil val=3> ]

но с помощью sort_by выдает ошибку, потому что время равно nil.

Я использую уродливый способ сортировки прямо сейчас, но я уверен, что есть хороший способ сделать это

starred=[]
@answers.each {|a| (starred << a) if a.starred }
@[email protected]
starred=starred.sort_by {|a| a.starred }.reverse
@[email protected]
4b9b3361

Ответ 1

starred.sort_by { |a| [a ? 1 : 0, a] }

Когда ему приходится сравнивать два элемента, он сравнивает массивы. Когда Ruby сравнивает массивы (вызывает метод ===), он сравнивает 1-й элемент и переходит во 2-й элемент только в том случае, если первые равны. ? 1 : 0 garantees, у нас будет Fixnum как 1-й элемент, поэтому он не должен быть ошибкой.

Если вы выполните ? 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]

Ответ 2

Если вы хотите, чтобы nils отображались сначала (нуль-эквивалент):

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

Если вы хотите, чтобы они отображались последними, вы можете заменить ноль на Max Int, но это кажется слишком взломанным. Это может быть лучше:

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

Ответ, предоставленный Накилоном, блестящий, хотя вы по существу сортируете дважды, по двум различным атрибутам. Для большинства ситуаций это, вероятно, достаточно.

Ответ 3

Просто используйте value.to_i

starred.sort_by { |a| a.to_i }.reverse