23283

[code]

    ary1 = [[2, 5, 9], [5, 5, 6], [2, 6, 8], [2, 5, 7]]
    ary2 = [[2, 9, 5], [5, 6, 5], [8, 6, 2], [7, 2, 5]]
    
    # 最大値の小さい順
    p ary1.sort{|a, b| a.max <=> b.max}
    p ary2.sort{|a, b| a.max <=> b.max}
    p ''
    # 最大値の大きい順
    p ary1.sort{|a, b| b.max <=> a.max}
    p ary2.sort{|a, b| b.max <=> a.max}
    p ''
    # 最小値の小さい順
    p ary1.sort{|a, b| a.min <=> b.min}
    p ary2.sort{|a, b| a.min <=> b.min}
    p ''
    # 最小値の大きい順
    p ary1.sort{|a, b| b.min <=> a.min}
    p ary2.sort{|a, b| b.min <=> a.min}
    
[/code]

出力結果  
[[5, 5, 6], [2, 5, 7], [2, 6, 8], [2, 5, 9]]  
[[5, 6, 5], [7, 2, 5], [8, 6, 2], [2, 9, 5]]  
""  
[[2, 5, 9], [2, 6, 8], [2, 5, 7], [5, 5, 6]]  
[[2, 9, 5], [8, 6, 2], [7, 2, 5], [5, 6, 5]]  
""  
[[2, 5, 9], [2, 5, 7], [2, 6, 8], [5, 5, 6]]  
[[2, 9, 5], [7, 2, 5], [8, 6, 2], [5, 6, 5]]  
""  
[[5, 5, 6], [2, 6, 8], [2, 5, 9], [2, 5, 7]]  
[[5, 6, 5], [8, 6, 2], [2, 9, 5], [7, 2, 5]]

四つ目が（たまたまかもしれませんが）[2, 6, 8], [2, 5, 9], [2, 5, 7]の順となっているのに、  
三つめが[2, 5, 9], [2, 5, 7], [2, 6, 8]の順となっています。

そこで質問なのですが、  
ブロックの部分を  
a.min <=> b.min  
から  
b.min <=> a.min  
と逆にしても得られる結果は  
ちょうど逆の並びにならない理由を教えてください。  
また、三つめの例で  
**最小値が同じ場合は、次に小さいもの同士を比べ、小さい順に並べ  
さらに同じ場合は、その次に小さいもの同士を比べ、小さい順に並べる**  
ようにするにはどうすればいいですか？

（追記）  
三つめの例を  
**最小値が同じ場合は、次に小さいもの同士を比べ、小さい順に並べ  
さらに同じ場合は、その次に小さいもの同士を比べ、小さい順に並べる**  
ようにする簡単な方法はあるようですが、  
一つ目の例を  
**最大値が同じ場合は、次に大きいもの同士を比べ、小さい順に並べ  
さらに同じ場合は、その次に大きいもの同士を比べ、小さい順に並べる**  
また二つ目の例を  
**最大値が同じ場合は、次に大きいもの同士を比べ、大きい順に並べ  
さらに同じ場合は、その次に大きいもの同士を比べ、大きい順に並べる**  
さらに四つ目の例を  
**最小値が同じ場合は、次に小さいもの同士を比べ、大きい順に並べ  
さらに同じ場合は、その次に小さいもの同士を比べ、大きい順に並べる**  
ようにする簡単な方法はあるのでしょうか？


CC BY-SA 3.0
2016-03-19T13:50:57.350
23279
2016-03-20T15:49:56.267
2016-03-19T17:33:35.300
5363
5363
question
ruby
配列を最大値の小さい順、大きい順や最小値の小さい順、大きい順に並べ変えたときの結果について


_ちょうど逆の並びにならない理由を教えてください。_  
sortに用いられるアルゴリズムによってはキーに用いる値が同点と判定された場合の結果の並びが元の順序からは容易に判定できないものがあります。  
(Wikipediaの[ソート](https://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%BC%E3%83%88)や[安定ソート](https://ja.wikipedia.org/wiki/%E5%AE%89%E5%AE%9A%E3%82%BD%E3%83%BC%E3%83%88)などを参照してください。)  
rubyのsortメソッドでは、非安定ソートアルゴリズムの代表格であるクイックソートが使われているようですので、キーが同じ場合の結果は不定(正確には「容易には判定できない順序」であって、同じ入力に対しては通常必ず同じ結果になると思われます)となります。

また、あなたが与えているブロック`a.min <=> b.min`では、キーに使う値が同点であれば(`[2, 6, 8], [2, 5, 9], [2,
5,
7]`の場合、キーとして比較に使われる値は全部2)それらはソートアルゴリズム上は区別できませんので、不定(上記の意味)または元の順序を保存、と言うことになり、(たとえクイックソート以外のアルゴリズムでソートしたとしても)逆順にはなりません。

**_最小値が同じ場合は、次に小さいもの同士を比べ、小さい順に並べ  
さらに同じ場合は、その次に小さいもの同士を比べ、小さい順に並べる**  
とするにはどうすればいいですか？_  
「次に小さいもの」をどう定義するか(同点の値がある場合)にもよりますが、内側の配列の順序を変えても良いなら、「内側の配列を小さいもの順に並び替えて、その結果を(配列の辞書式比較で)さらに並べ替える」なんてことで実現できそうです。

[code]

    ary1.map{|arr|arr.sort}.sort
    => [[2, 5, 7], [2, 5, 9], [2, 6, 8], [5, 5, 6]] 
    ary2.map{|arr|arr.sort}.sort
    => [[2, 5, 7], [2, 5, 9], [2, 6, 8], [5, 5, 6]]
    
[/code]

内側の配列の順序を変更したくないというのであれば、「元の配列と並べ換えに使う値をペアにしてソートした後、『並べ換えに使う値』だけを剥ぎ取ってしまう」と言う形で実装するとこんな感じになりますね。

[code]

    ary1.map{|arr|[arr,arr.sort]}.sort{|p1,p2|p1[1]<=>p2[1]}.map{|p|p[0]}
    => [[2, 5, 7], [2, 5, 9], [2, 6, 8], [5, 5, 6]]
    ary2.map{|arr|[arr,arr.sort]}.sort{|p1,p2|p1[1]<=>p2[1]}.map{|p|p[0]}
    => [[7, 2, 5], [2, 9, 5], [8, 6, 2], [5, 6, 5]]  
    
[/code]

少しわかりにくければ、メソッドチェーンにせずに途中経過を表示させながら試してみてください。

他にもっと良いやり方がありそうですが、一つの例としてお読みください。


CC BY-SA 3.0
2016-03-19T14:43:25.757
23280
2016-03-19T14:43:25.757
13972
23279
answer


1つ目の質問はLe Pere d'OOさんの回答のとおりで、2つ目の質問について。

> 最小値が同じ場合は、次に小さいもの同士を比べ、小さい順に並べ  
>  さらに同じ場合は、その次に小さいもの同士を比べ、小さい順に並べる

要素をsortした結果を[Array#<=>](http://docs.ruby-
lang.org/ja/2.3.0/method/Array/i/=3c=3d=3e.html)に丸投げするのが楽かと思います。

[code]

    ary1.sort_by(&:sort)
    #  => [[2, 5, 7], [2, 5, 9], [2, 6, 8], [5, 5, 6]] 
    ary2.sort_by(&:sort)
    #  => [[7, 2, 5], [2, 9, 5], [8, 6, 2], [5, 6, 5]] 
    
[/code]

**追記**

質問の追記分について。いずれも単なる組み合わせです。

> 一つ目の例を  
>  最大値が同じ場合は、次に大きいもの同士を比べ、小さい順に並べ  
>  さらに同じ場合は、その次に大きいもの同士を比べ、小さい順に並べる

→要素を降順ソートした値で、昇順ソート

[code]

    ary1.sort_by {|x| x.sort {|a, b| b <=> a} }
    
[/code]

> また二つ目の例を  
>  最大値が同じ場合は、次に大きいもの同士を比べ、大きい順に並べ  
>  さらに同じ場合は、その次に大きいもの同士を比べ、大きい順に並べる

→要素を降順ソートした値で、降順ソート

[code]

    ary1.sort_by {|x| x.sort {|a, b| b <=> a} }.reverse
    
[/code]

> さらに四つ目の例を  
>  最小値が同じ場合は、次に小さいもの同士を比べ、大きい順に並べ  
>  さらに同じ場合は、その次に小さいもの同士を比べ、大きい順に並べる

→要素を昇順ソートした値で、降順ソート

[code]

    ary1.sort_by(&:sort).reverse
    
[/code]


CC BY-SA 3.0
2016-03-19T16:40:17.080
23283
2016-03-20T15:49:56.267
2016-03-20T15:49:56.267
4010
4010
23279
answer