1

place次のパラメーターを持つオブジェクトphonecategoryあります: street、、、、、。zipwebsite

オブジェクトの配列もあり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

は、 のレールシズムとsum(&:last)同等であることに注意してください。sum{|k,v| v}reduce(0){|sum, (k,v)| sum += v}

于 2012-11-11T23:39:22.497 に答える
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オブジェクトのサブハッシュを作成しています。valuespresent?

次に、このサブハッシュinjectで、ハッシュに入れた熟考された値を合計する呼び出しを行いますvalues。最後に、すべてを逆にして、最初に最高のスコアを取得します。

きれいにするために、提案されたマークのように、モデルのインスタンスメソッドで各オブジェクトのスコアを計算するメソッドを実装することをお勧めします

于 2012-11-11T23:27:33.697 に答える
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 に答える