按字段可用性排序对象

时间:2012-11-11 22:47:39

标签: ruby-on-rails ruby sorting

我有一个place对象,其中包含以下参数:phonecategorystreetzipwebsite

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

根据参数可用性对place数组进行排序的最佳方法是什么?即,如果place1具有最多可用参数,或者nil参数的数量最少,则应首先将其重新排序,依此类推。

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

3 个答案:

答案 0 :(得分: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解决方案:

我认为这是一个ActiveRecord模型,因为 Ruby on Rails 标记。由于这是非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

请注意,sum(&:last)相当于sum{|k,v| v},后者又是reduce(0){|sum, (k,v)| sum += v}的铁路。

答案 1 :(得分: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哈希中的键值对来创建ActiveRecord对象的values的子哈希,并且只有当它们有{{{ 1}}值。

然后在这个子哈希上,我们正在调用present?,它将我们放在inject哈希中的重要值加起来。最后,我们反转所有内容,以便您获得最高分。

为了使其干净,我建议你实现一个方法来计算模型中实例方法中每个对象的分数,比如标记建议

答案 2 :(得分: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

这可以通过使用Enumerable的count和块来缩短它:

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