Безопасно и эффективно сортировать по отсутствующим атрибутам? - PullRequest
2 голосов
/ 10 августа 2010

Вот что я делаю:

offers = v.offers.sort { |a,b| a.expires <=> b.expires }

Эти данные загружаются через ActiveResource (поэтому каждый набор атрибутов экземпляра определяется данными, которые он содержит). Однако недавнее изменение входящих данных сделало атрибут expires необязательным. Есть ли изменение определения класса, из-за которого метод сортировки получает значение по умолчанию, если атрибут отсутствует в экземпляре?

редактировать: @ Никита

Похоже, все будет не так просто:

o.expires == nil?
NoMethodError: undefined method `expires' for #<Offer:0x00000100d3faa8>

o.expires?
=> nil

поэтому я попытался:

offers.sort{|a,b|
if a.expires?
    b.expires? ? 0 : -1
else
    b.expires? ? 1 : a.expires <=> b.expires
end
}

NoMethodError: undefined method `expires' for #<Offer:0x00000100d3faa8>

Я надеялся, что смогу обновить определение класса примерно так:

expires ||= ""

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

обновление

offers.sort{|a,b|
if defined? a.expires == nil
    (defined? b.expires == nil) ? 0 : -1
else
    (defined? b.expires == nil) ? 1 : a.expires <=> b.expires
end
}

ArgumentError: comparison of Offer with Offer failed

from (irb):70:in `sort'
from (irb):70
from /usr/local/lib/ruby/gems/1.9.1/gems/railties-3.0.0.beta4/lib/rails/commands/console.rb:47:in `start'
from /usr/local/lib/ruby/gems/1.9.1/gems/railties-3.0.0.beta4/lib/rails/commands/console.rb:8:in `start'
from /usr/local/lib/ruby/gems/1.9.1/gems/railties-3.0.0.beta4/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'

Ура за многословие; p

Ответы [ 2 ]

1 голос
/ 10 августа 2010

Ого, не нужно, чтобы это было безобразно.

offers.sort_by {|o| o.expires || ""}
1 голос
/ 10 августа 2010

Я не понимаю, какое «определение класса» вы хотите. Разве адаптация блока сортировки не решит проблему?

if a.expires == nil
    b.expires == nil ? 0 : -1
else
    b.expires == nil ? 1 : a.expires <=> b.expires
end

при обновлении
Понимаю. В ruby ​​есть оператор defined?, который может помочь. Возвращает ноль или строку, представляющую тип элемента (например, «метод»).

if defined? a.expires == nil
    (defined? b.expires == nil) ? 0 : -1
else
    (defined? b.expires == nil) ? 1 : a.expires <=> b.expires
end

Я пока не очень понимаю, как работают блоки сортировки.
Это легко. Он должен возвращать -1, 0 или 1 в зависимости от того, меньше ли первый элемент, равен или больше второго.
<=> оператор делает более или менее одно и то же:

1 <=> 2 # result is -1
2 <=> 2 # result is 0
15 <=> 2 # result is 1

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

class Offer
  def initialize(e)
    @expires = e
  end

  def expires
    @expires
  end
end
offers = [Offer.new(3), Offer.new(1), Offer.new(2), Object.new]


offers.sort! { |a, b|
  if (defined? a.expires) == nil
    ((defined? b.expires) == nil) ? 0 : -1
  else
    ((defined? b.expires) == nil) ? 1 : a.expires <=> b.expires
  end
}
puts offers.inspect

Ваша ошибка указывает, что a.expires имеет тип Offer, который нельзя сравнивать.

Ура для многословия; p
Добро пожаловать на рельсы:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...