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

Сортировка массива ruby ​​объектов по атрибуту, который может быть nil

У меня есть массив объектов, которые мне нужно отсортировать по атрибуту position, который может быть целым или нулевым, и мне нужны объекты, у которых позиция nil находится в конце массива. Теперь я могу заставить позицию вернуть некоторое значение, а не nil, чтобы array.sort не терпел неудачу, но если я использую 0 в качестве этого значения по умолчанию, тогда он помещает эти объекты в начало сортировки. Какой лучший способ сделать это? должен ли я просто устанавливать значения nil на какое-то смехотворно большое число, которое "почти" всегда гарантировано в конце? или есть какой-то другой способ, я могу заставить метод array.sort помещать объекты атрибута nil в конец массива? код выглядит следующим образом:

class Parent
  def sorted_children
     children.sort{|a, b| a.position <=> b.position}
  end
end

class Child
  def position
    category ? category.position : #what should the else be??
  end
end

теперь, если я сделаю 'else' чем-то вроде 1000000000, то он, скорее всего, поместит их в конец массива, но мне не нравится это решение, поскольку оно произвольно

4b9b3361

Ответ 1

Как насчет Child в определении <=> основываться на category.position, если существует category, и сортировка элементов без category, как всегда, больше, чем с category?

class Child
  # Not strictly necessary, but will define other comparisons based on <=>
  include Comparable   
  def <=> other
    return 0 if !category && !other.category
    return 1 if !category
    return -1 if !other.category
    category.position <=> other.category.position
  end
end

Затем в Parent вы можете просто вызвать children.sort.

Ответ 2

Я бы просто подстроил ваш вид, чтобы положить nil элементы last. Попробуйте что-то вроде этого.

foo = [nil, -3, 100, 4, 6, nil, 4, nil, 23]

foo.sort { |a,b| a && b ? a <=> b : a ? -1 : 1 }

=> [-3, 4, 4, 6, 23, 100, nil, nil, nil]

Это говорит о том, что если a и b являются не-nil, они обычно сортируются, но если один из них равен нулю, верните статус, который больше чем один.

Ответ 3

Я обрабатываю такие вещи, как это:

 children.sort_by {|child| [child.position ? 0 : 1,child.position || 0]}

Ответ 4

Справедливости ради, я не очень хорошо знаком с Ruby, так что считайте это скорее идеей алгоритма, а не кодом... и перепишите оператор?: как любой Ruby имеет этот чист.

Не можете ли вы просто проверить нуль в сравнении:

class Parent
  def sorted_children
     children.sort{|a,b|( a and b ) ? a <=> b : ( a ? -1 : 1 ) }
  end
end

Отредактировано для использования кода Glenra, который реализует то же самое, что и мой, но в меньшем (и, вероятно, более легко читаемом) количестве кода.

Ответ 5

Я не делал Ruby через некоторое время, но вы могли бы разделить нулевую проверку на сортировку (и просто разрешить Child # position для возврата null):

def sorted_children
  children.reject{|c| c.position.nil?}.sort_by(&:position) +
    children.select{|c| c.position.nil?}
end

По общему признанию, это не самое эффективное решение, но оно не имеет никаких магических чисел.

Ответ 6

Вы можете сделать это без переопределения оператора космического корабля путем определения нового метода сравнения.

class Child
  include Comparable   
  def compare_by_category(other)
    return 0 if !category && !other.category
    return 1 if !category
    return -1 if !other.category
    category.position <=> other.category.position
  end
end

Метод sort может принимать блок, поэтому вы можете отсортировать его с помощью этого нового метода:

children.sort {|a,b| a.compare_by_category(b) }

Ответ 7

Самое простое решение для меня это

def sorted_children(children)
  children.sort_by { |child| child.position || -1}
end