整数またはnilの位置属性で並べ替える必要のあるオブジェクトの配列があり、nilの位置にあるオブジェクトが配列の末尾にある必要があります。これで、array.sortが失敗しないように、位置にnilではなく値を強制的に返すことができますが、このデフォルトとして0を使用すると、これらのオブジェクトが並べ替えの先頭に配置されます。この種類を行うための最良の方法は何ですか? nil値を、「ほとんど」常に最後にあることが保証されている途方もなく高い数に設定する必要がありますか?または、array.sortメソッドでnil属性オブジェクトを配列の最後に配置する他の方法はありますか?コードは次のようになります。
class Parent
def sorted_children
children.sort{|a, b| a.position <=> b.position}
end
end
class Child
def position
category ? category.position : #what should the else be??
end
end
ここで、「else」を1000000000のようなものにすると、配列の最後に配置される可能性が高くなりますが、この解決策は任意なので、私は好きではありません
Child
が存在する場合にcategory
が存在する場合は<=>
に基づいてcategory.position
を定義し、category
のない項目を常により大きく並べ替えるcategory
?
class Child
# Not strictly necessary, but will define other comparisons based on <=>
include Comparable
def <=> other
return 0 if !category && !other.category
return 1 if !category
return -1 if !other.category
category.position <=> other.category.position
end
end
次に、Parent
でchildren.sort
を呼び出すだけです。
nil
個のアイテムが最後になるように、並べ替えを調整します。このようなものを試してください。
foo = [nil, -3, 100, 4, 6, nil, 4, nil, 23]
foo.sort { |a,b| a && b ? a <=> b : a ? -1 : 1 }
=> [-3, 4, 4, 6, 23, 100, nil, nil, nil]
つまり、aとbの両方が非nilの場合、通常は並べ替えられますが、どちらかがnilの場合は、1つ大きい順に並べ替えるステータスを返します。
私はこれらの種類のものをこのように扱います:
children.sort_by {|child| [child.position ? 0 : 1,child.position || 0]}
公平を期すために、私はRubyにあまり慣れていないので、これをコードではなくアルゴリズムのアイデアと考えてください。そして、::演算子を次のように書き換えてくださいRubyクリーナー。
比較でnilをチェックすることはできませんか?
class Parent
def sorted_children
children.sort{|a,b|( a and b ) ? a <=> b : ( a ? -1 : 1 ) }
end
end
Glenraのコードを使用するように編集しました。これは、私のものと同じものを実装しますが、コードの量が少なく(おそらく読みやすく)なります。
私にとって最も簡単な解決策は
def sorted_children(children)
children.sort_by { |child| child.position || -1}
end
これは、新しい比較メソッドを定義することにより、宇宙船オペレーターをオーバーライドせずに行うことができます。
class Child
include Comparable
def compare_by_category(other)
return 0 if !category && !other.category
return 1 if !category
return -1 if !other.category
category.position <=> other.category.position
end
end
sort
メソッドはブロックを取ることができるため、この新しいメソッドを使用して並べ替えることができます。
children.sort {|a,b| a.compare_by_category(b) }
Rubyはしばらく実行していませんが、並べ替えからnullチェックを分割できます(Child#positionがnullを返すことを許可するだけです)。
def sorted_children
children.reject{|c| c.position.nil?}.sort_by(&:position) +
children.select{|c| c.position.nil?}
end
確かに、これは最も効率的なソリューションではありませんが、マジックナンバーがありません。