LeetCodeの問題を解いていたんですが、sortメソッドとsort_byメソッドの違いがわからず解答に時間がかかったため、備忘録としてまとめます。
記事の信頼性
- ぼくは独学で未経験から従業員300名以上の自社開発企業へ転職しました。
- 実務ではVue.jsとRailsを毎日書いています。
- 初心者や駆け出しエンジニアがつまづくポイントも身をもってよく理解しています。
問題
LeetCodeの791. Custom Sort Stringという問題を解いており、次の解答を作成しました。
def custom_sort_string(order, s)
order_hash = Hash.new(0)
order.each_char.with_index do |char, i|
order_hash[char] = i
end
s.chars.sort { |char| order_hash[char] }.join
endしかしこれだと、下記のテストケースで失敗してしまいます。
入力値: order = "exv", s = "xwvee"
実際の出力結果: "weevx"
期待する出力結果: "eexvw"そこで解答のsortメソッドの部分をsort_byに変更したところ、すべてのテストケースで成功しました。
しかし、sortとsort_byの違いがわかっていないため、なぜこの変更でうまくいくようになったかが分かりませんでした、、。
解決方法
sortとsort_byのちがいを理解することで、納得できました。
sort メソッドの挙動
sortメソッドは単に配列の要素同士を直接比較するだけです。
比較には<=>演算子(宇宙船演算子)が使われます。
<=>演算子は、二つの値を比較し、左辺が右辺より小さければ-1、等しければ0、大きければ1を返します。
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
puts numbers.sort.inspect
#=> [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
fruits = ["banana", "apple", "pear", "orange"]
puts fruits.sort.inspect
#=> ["apple", "banana", "orange", "pear"]なおinspectメソッドは、オブジェクトを人間が読みやすい文字列形式で返します。
ここでは、配列の中身を見やすく表示するために使っています。
sort_by メソッドの挙動
sort_byメソッドは、ブロックを渡して使います。
ブロックの評価結果をキーとして、要素どうしを並び替えます。
# 文字列の長さで昇順にソート
fruits = ["banana", "apple", "pear", "orange"]
puts fruits.sort_by { |fruit| fruit.length }.inspect
#=> ["pear", "apple", "banana", "orange"]
# ハッシュのバリューでソート
fruits_hash = { "banana" => 5, "apple" => 3, "pear" => 4, "orange" => 6 }
puts fruits_hash.sort_by { |_, value| value }.inspect
#=> [["apple", 3], ["pear", 4], ["banana", 5], ["orange", 6]]冒頭のLeetCodeの解答の場合、order_hash[char]の結果をキーにソートしたかったため、sort_byを使うべきでした。
def custom_sort_string(order, s)
order_hash = Hash.new(0)
order.each_char.with_index do |char, i|
order_hash[char] = i
end
# sort ではなく sort_by を使う
s.chars.sort_by { |char| order_hash[char] }.join
endこれで無事に問題を解くことができました!
おわりに
アルゴリズム系の問題をソートを使って解く場合は、sortとsort_byをしっかり使い分けます。
- 比較キーが単純な場合(数値や文字列の大小関係など)は
sortを使う。 - 比較キーが複雑な場合(別の値に基づいてソートするなど)は
sort_byを使う。
コメント