ruby sort_by! для массива объектов - PullRequest
0 голосов
/ 30 октября 2018

Хорошо, я ЗНАЮ, что я просто делаю что-то глупое, но я просто не могу заставить это работать.

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

class Opportunity
  attr_accessor :effort
  attr_accessor :value

  def initialize(effort,value)
    # set values to 1 + the Rayleigh distribution (rounded) 
    @effort = 1 + (effort * Math.sqrt(0-2*Math.log(1-rand()))).round
    @value = 1 + (value * Math.sqrt(0-2*Math.log(1-rand()))).round
  end
end

Я помещаю эти наборы в массив (это свойство другого объекта), а затем хочу отсортировать их по определенным свойствам (например, усилию)

    # Order the working backlog
    #  (see https://ruby-doc.org/core-2.4.3/Array.html#method-i-sort_by-21)
    puts workingBacklog.backlog[0].effort
    workingBacklog.backlog.sort_by! {|opA,opB| opA.effort <=> opB.effort }

Вот пример вывода ...

6
3cmc.rb:57:in `block (2 levels) in <main>': undefined method `effort' for 
nil:NilClass (NoMethodError)
    from 3cmc.rb:57:in `each'
    from 3cmc.rb:57:in `sort_by'
    from 3cmc.rb:57:in `sort_by!'
    from 3cmc.rb:57:in `block in <main>'
    from 3cmc.rb:51:in `each'
    from 3cmc.rb:51:in `<main>'

Так что я ЗНАЮ, что там есть массив объектов, отличных от NULL, потому что «6» в первой строке вывода не равен NULL. Но сразу после этого похоже, что колеса пословиц отрываются. Что, черт возьми, здесь происходит?

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Сначала исправьте sort_by согласно ответу @ tadman .

backlog.sort_by!(&:effort)

Так что я ЗНАЮ, что там есть массив объектов, отличных от NULL, потому что "6" в первой строке вывода не равен NULL.

Вы проверили только первый элемент workingBacklog.backlog. Еще может быть nil где-то еще в вашем backlog массиве.

Ищите nil с select.with_index.

backlog.select.with_index { |obj,idx|
  puts "nil at #{idx}" if obj == nil
}

Вот пример, который также воспроизводит ошибку.

backlog = [Opportunity.new(3, 4), nil]
puts backlog[0].effort
backlog.sort_by!(&:effort)

4    
/Users/schwern/tmp/test.rb:16:in `each': undefined method `effort' for nil:NilClass (NoMethodError)
    from /Users/schwern/tmp/test.rb:16:in `sort_by'
    from /Users/schwern/tmp/test.rb:16:in `sort_by!'
    from /Users/schwern/tmp/test.rb:16:in `<main>'
0 голосов
/ 30 октября 2018

Метод sort требует блока сравнения (a и b), но метод sort_by принимает только один аргумент, сортируемый элемент, и вы должны вернуть преобразованную версию в случае необходимости, так, как вы хочу отсортировать.

В вашем случае это так:

backlog.sort_by! { |e| e.effort }

Или более кратко:

backlog.sort_by!(&:effort)

Ваш оригинальный код будет работать, если вы используете правильный метод:

backlog.sort! {|opA,opB| opA.effort <=> opB.effort }

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

ПРИМЕЧАНИЕ: В Ruby заглавные буквы имеют значительный контекстный смысл, поэтому имена переменных и методов должны быть только в lower_case форме. Столицы зарезервированы для ClassName и CONSTANT_NAME ситуаций.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...