1

我有一个place具有以下参数的对象:phone, category, street, zip, website.

我还有一个place对象数组:[place1, place2, place3, place4, place5].

place根据参数可用性对 s 数组进行排序的最佳方法是什么?即,如果place1有最多可用的参数,或最少的参数nil,它应该重新排序到第一个,依此类推。

编辑:这些对象不是ActiveRecord对象

4

3 回答 3

5

我会让每个 Place 对象知道它有多完整:

class Place
  attr_accessor :phone, :category, :street, :website, :zip

  def completeness
    attributes.count{|_,value| value.present?}
  end
end

然后很容易按完整性对您的地点对象进行排序:

places.sort_by(&:completeness)

编辑:非 ActiveRecord 解决方案:

由于Ruby on Rails标签,我曾假设这是一个 ActiveRecord 模型。由于这是一个非 ActiveRecord 模型,因此您可以instance_variables使用attributes. (顺便说一句,恭喜你知道 Rails 中的领域模型不必从 ActiveRecord 继承)

class Place
  attr_accessor :phone, :category, :street, :website, :zip

  def completeness
    instance_variables.count{|v| instance_variable_get(v).present?}
  end
end

编辑 2:加权属性

您对计算加权分数有意见。在这种情况下,或者当您想要选择特定属性时,您可以在模型中添加以下内容:

  ATTR_WEIGHTS = {phone:1, category:1, street:2, website:1, zip:2}

  def completeness
    ATTR_WEIGHTS.select{|k,v| instance_variable_get(k).present?}.sum(&:last)
  end

请注意, thesum(&:last)等价于sum{|k,v| v}which 又是reduce(0){|sum, (k,v)| sum += v}.

于 2012-11-11T23:39:22.497 回答
0

如果你有一堂课Place

class Place
  attr_accessor :phone, :category, :street, :website, :zip
end

然后创建一个实例place1

place1 = Place.new
place1.instance_variables      # => []
place1.instance_variables.size # => 0

place1.phone = '555-1212'      # => "555-1212"
place1.instance_variables      # => [ :@phone ]
place1.instance_variables.size # => 1

并创建下一个实例:

place2 = Place.new
place2.phone = '555-1212'
place2.zip   = '00000'
place2.instance_variables      # => [ :@phone, :@zip ]
place2.instance_variables.size # => 2

您可以按已设置的实例变量的升序排序:

[place1, place2].sort_by{ |p| p.instance_variables.size }
# => [ #<Place:0x007fa8a32b51a8 @phone="555-1212">, #<Place:0x007fa8a31f5380 @phone="555-1212", @zip="00000"> ]

或按降序排序:

[place1, place2].sort_by{ |p| p.instance_variables.size }.reverse
# => [ #<Place:0x007fa8a31f5380 @phone="555-1212", @zip="00000">, #<Place:0x007fa8a32b51a8 @phone="555-1212"> ]

这使用基本的 Ruby 对象,不需要 Rails,它会询问对象实例本身设置了什么,因此您不必维护任何外部属性列表。

注意:如果您将实例变量设置为某个值,然后将其设置回nil.

这修复了它:

[place1,place2].sort_by{ |p|
  p.instance_variables.reject{ |v|
    p.instance_variable_get(v).nil? 
  }.size
}.reverse

这通过使用count带有块的 Enumerable 来缩短它:

[place1,place2].sort_by{ |p|
  p.instance_variables.count{ |v|
    !p.instance_variable_get(v).nil? 
  }
}.reverse
于 2012-11-12T01:09:11.633 回答
0

我确信有更好的方法,但这是一个开始:

红宝石脂肪一班轮

values = {phone: 5, category: 3, street: 5, website: 3, zip: 5} #Edit these values to ponderate.
array = [place1, place2, place3, place4, place5]

sorted_array = array.sort_by{ |b| b.attributes.select{ |k, v| values.keys.include?(k.to_sym) && v.present? }.inject(0){ |sum, n| sum + values[n[0]] } }.reverse

因此,我们基本上是attributes通过仅选择散列中的键值对values并且仅当它们具有present?值时才创建 ActiveRecord 对象的子散列。

然后在这个子散列上,我们调用inject它将对我们放入values散列中的计算值求和。最后,我们反转所有内容,以便您首先获得最高分。

为了使它干净,我建议您实现一个方法,该方法将计算模型中实例方法中每个对象的分数,如标记建议

于 2012-11-11T23:27:33.697 回答