我有一个place
对象,其中包含以下参数:phone
,category
,street
,zip
,website
。
我还有一组place
个对象:[place1, place2, place3, place4, place5]
。
根据参数可用性对place
数组进行排序的最佳方法是什么?即,如果place1
具有最多可用参数,或者nil
参数的数量最少,则应首先将其重新排序,依此类推。
编辑:这些对象不是ActiveRecord
个对象
答案 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