初学者向けの記事です。
二次元配列(配列の中に配列が入れ子になっている)のsort_byの挙動について、大分混乱したのでメモ的に残しておきます。
*その前にsort_byメソッドはこちらの解説がわかりやすいです。
array = [[1, 6], [3, 4], [2, 5], [1, 7]]
sorted_array = array.sort_by { |a| a}
puts sorted_array.inspect
# 出力:[[1, 6], [1, 7], [2, 5], [3, 4]]
二次元配列のソートでは、サブ配列(配列の中の配列)の最初の要素を比較してソートが行われる。最初の要素が同じ場合は、次の要素を比較して順序を決定する。つまり、サブ配列は最初の要素で主に昇順に並べられ、同じ最初の要素を持つサブ配列がある場合は、次の要素で昇順にソートされる。
配列[[1, 6], [3, 4], [2, 5], [1, 7]]
では、最初の要素1, 3, 2, 1を基にソートされる。まず1と1が最小で、次に2、最後に3が続く。1を最初の要素に持つサブ配列[1, 6]
と[1, 7]
は、次の要素である6と7を比較してさらにソートされる。その結果、ソート後の配列は[[1, 6], [1, 7], [2, 5], [3, 4]]
となる。
array = [[1, 6], [3, 4], [2, 5], [1, 7]]
sorted_array = array.sort_by { |a,b| [-a, b] }
puts sorted_array.inspect
# 出力:[[3, 4], [2, 5], [1, 6], [1, 7]]
{ |a, b| [-a, b] }でサブ配列の最初の要素aを降順で、次の要素bを昇順でソートする。まず最初の要素に基づいて[3, 4]
が最も先に来る(最初の要素が最大のため)。次に[2, 5]
、そして最初の要素が1である[1, 6]
と[1, 7]
が続く。これらは最初の要素が同じであるため、次の要素に基づいて昇順に並べられる。その結果、最終的なソート結果は[[3, 4], [2, 5], [1, 6], [1, 7]]
となる。
array = [[1, 6], [3, 4], [2, 5], [1, 7]]
sorted_array = array.sort_by { |a,b| [-a, -b] }
puts sorted_array.inspect
# 出力:[[3, 4], [2, 5], [1, 7], [1, 6]]
{ |a, b| [-a, -b] }でサブ配列の最初の要素aを降順で、次の要素bも降順でソートする。-aと-bにより、それぞれの要素が負の値として評価され、ソート時にはその絶対値が大きいものから小さいものへと順序が決定される。つまり、最初の要素aに関しては、最大の値から順に配列が並べられ、最初の要素が同じ場合は次の要素bが大きいものから順に並べられる。
最初の要素に基づき[3, 4]
が最先に配置される。続いて[2, 5]
が来る。最初の要素が1である[1, 6]
と[1, 7]
の場合、次の要素に基づいて降順にソートされるため、[1, 7]
が[1, 6]
より先にくる。
結果として得られる配列は[[3, 4], [2, 5], [1, 7], [1, 6]]
になる。
値を[[1, 6], [3, 4], [8, 6], [1, 7]]
に変えて
array = [[1, 6], [3, 4], [8, 6], [1, 7]]
sorted_array = array.sort_by { |a,b| [-b, -a] }
puts sorted_array.inspect
# 出力:[[1, 7], [8, 6], [1, 6], [3, 4]]
{ |a, b| [-b, -a] }で各サブ配列の第二要素bを主な基準として降順、第一要素aをその次の基準として降順でソートする。
このソート基準では、-b
と-a
を使ってそれぞれの要素を負の数として扱い、結果として大きい数から小さい数へと降順にソートする。この場合、サブ配列の第二要素がソートの最初の基準で、第一要素は第二要素が同じサブ配列間でのソート基準になる。
配列[[1, 6], [3, 4], [8, 6], [1, 7]]
をこの条件でソートすると、まず第二要素に基づいて降順にソートされる。最大の第二要素は7
で、これに対応するサブ配列は[1, 7]
となる。次に第二要素が6
であるサブ配列があり、その中で第一要素が大きい[8, 6]
が先に来る。同じく第二要素が6
の[1, 6]
が次に続く。最後に第二要素が最小の4
である[3, 4]
が来る。
したがって、ソート後の配列は[[1, 7], [8, 6], [1, 6], [3, 4]]
となる。