安全&有效地排序可能缺失的属性?

时间:2010-08-10 02:14:33

标签: ruby-on-rails ruby

这就是我正在做的事情:

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

此数据通过ActiveResource加载(因此每组实例属性由其包含的数据定义)。但是,最近传入数据的更改使“expires”属性成为可选项。是否存在类定义更改,如果实例中缺少该属性,则会导致sort方法获取默认值?

编辑:@Nikita

看起来不会那么简单:

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 个答案:

答案 0 :(得分:1)

我没有得到你想要的'类定义'。是不是只是调整排序块来解决问题?

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


我知道了。 ruby中有一个defined?运算符可能会有所帮助。它返回nil或表示元素类型的字符串(如'method')。

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,无法进行比较。

Hooray的冗长; p
欢迎来到rails:)

答案 1 :(得分:1)

哇,不需要这个丑陋。

offers.sort_by {|o| o.expires || ""}