はじめに
Rubyの勉強してて、2次元配列のソートでつまずいたので、その時、調べた備忘録です。
さっそく本題
例)arr = [[1, 3], [1, 5], [1, 2], [2, 4], [2, 2]] をソートしたい
① arr[1]で昇順にソート
sort()
p arr.sort {|a,b| a[1] <=> b[1]}
# 値が数値、文字に関わらず有効
sort_by()
p arr.sort_by {|x| x[1]}
# 値が数値、文字に関わらず有効
② arr[1]で降順にソート
sort()
p arr.sort {|a,b| a[1] <=> b[1]}.reverse
# 昇順.reverse
# 値が数値、文字に関わらず有効
または
p arr.sort {|a,b| b[1] <=> a[1]}
# b<=>a
# 値が数値、文字に関わらず有効
sort_by()
p arr.sort_by {|x| x[1]}.reverse
# 昇順.reverse
# 値が数値、文字に関わらず有効
または
p arr.sort_by {|x| -x[1]}
# -x
# 値が数値のみ有効
③ arr[0]で昇順 -> arr[1]で昇順にソート
sort()
p arr.sort {|a, b| (a[0] <=> b[0]).nonzero? || (a[1] <=> b[1])}
# (第1キー).nonzero? || (第2キー)
# 値が数値、文字に関わらず有効
sort_by()
p arr.sort_by {|x| [x[0], x[1]]}
# [第1キー, 第2キー]
# 値が数値、文字に関わらず有効
④ arr[0]で昇順 -> arr[1]で降順にソート
sort()
p arr.sort {|a, b| (a[0] <=> b[0]).nonzero? || (b[1] <=> a[1])}
# 値が数値、文字に関わらず有効
sort_by()
p arr.sort_by {|x| [x[0], -x[1]]}
# 値が数値のみ有効
最後に
④のケースで文字配列に対して、sort_byを使用した方法が、どうしてもわかりませんでした。
そもそも出来るのかもわかりませんが、もしわかる方がいましたら、教えていただけると助かります。
追記
④のケースで、1つ考えてみました。
たぶん、期待通り動作すると思います。
注)この実装では、ソートが安定しません。
sort_by()
p arr.sort_by {|x| x[1]}.reverse.sort_by {|x| x[0]}
# sort_by(第2キー).reverse.sort_by(第1キー)
# 値が数値、文字に関わらず有効
一応、ベンチマークを取ってみたところ、sort()を使用したケースより、速かったです。
追記2
「追記」の実装、@HMMNRST さんよりご指摘をいただきました。
こちらの実装なら大丈夫そうです。
sort_by()
i = 0
p arr.sort_by {|x| [x[1], i += 1]}.reverse.sort_by {|x| [x[0], i += 1]}
# sort_by(第2キー).reverse.sort_by(第1キー)
# 値が数値、文字に関わらず有効