按字段可用性对对象进行排序



我有一个具有以下参数的place对象:phonecategorystreetzipwebsite

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

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

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

我会让每个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标签。由于这是非活动记录模型,因此您可以使用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}的轨道。

我相信有更好的方法可以做到这一点,但这是一个开始:

红宝石胖一衬垫

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

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

然后在这个子哈希上,我们调用inject,它将汇总我们在values哈希中放入的思考值。最后,我们反转一切,以便您首先获得最高分。

为了使其干净,我建议您实现一种方法,该方法将计算模型中实例方法中每个对象的分数,如 mark 建议的那样

如果你有一个类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来缩短它:

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

最新更新