このページでは、コレクションパイプラインパターンにおける操作について説明します。詳細については以下をご覧ください。
- コレクションパイプラインの記事:コレクションパイプラインパターンを説明する記事
- 操作カタログ:このページを作成した、選択された操作の一覧
ソート
出力は、指定された比較関数に基づいてソートされた入力のコピーです。
ソート演算子の最も単純な適用は、引数なしの単純な呼び出しです。
[3, 1, 4, 2].sort # => [1, 2, 3, 4]
(sort [3 1 4 2]) ;; => (1 2 3 4)
このように引数なしのソートは、ソート方法を知っているものに対して機能し、この場合昇順という事前に定義されたソート順になります。
ソート順を変更する最も簡単な方法は、ソートを逆順と組み合わせることです。
[3, 1, 4, 2].sort.reverse # => [4, 3, 2, 1]
(reverse(sort [3 1 4 2])) ;; => (4 3 2 1)
しかし、多くの場合、ソートする必要があるものに対する標準的なソート方法がないか、標準とは異なる方法でソートしたい場合があります。これを行う最も基本的な方法は、比較関数をソートに渡すことです。比較関数は2つの引数を取り、順序を示します。
["10", "8", "300"].sort {|a,b| a.to_i <=> b.to_i} # => ["8", "10", "300"]
(sort #(< (read-string %1) (read-string %2)) ["8" "10" "300"]) ;; => ("8" "10" "300")
ここには明らかに重複した部分があります。何かをソートしたい場合、ほぼ常にソートキーを取得するために両方の引数に対して同じ関数を呼び出します。上記の例では、この関数は文字列から数値への変換です。したがって、その関数を一度だけ指定するのが理にかなっています。
["10", "8", "300"].sort_by {|a| a.to_i} # => ["8", "10", "300"]
(sort-by read-string ["8" "10" "300"]) ;; => ("8" "10" "300")
これについてもう少し深く考えると、ソートを指定するときに必要な関数が2つあると考えます。1つの関数は、2つの値を比較してソート順を示す比較関数であり、もう1つの関数は、ソートされるコレクションの各要素に対して実行され、比較関数に渡される値を抽出するキー抽出関数です。
比較関数には2つのスタイルがあります。1つ目は、最初の引数が2番目の引数よりも小さいかどうかを示す「<」のようなブール比較関数です。順序を取得するには、このような比較関数は、テストされた値のペア間の関係がより小さいか、より大きいか、または等しいかを確認するために、各比較の両方向で使用する必要がある場合があります。(これが「<=」を使用してはならない理由です。)
2番目の形式の比較関数は、負の場合はより小さい、ゼロの場合は等しい、正の場合はより大きいことを意味する整数を返します。多くの言語で使用される「宇宙船」演算子「<=>」は、これの良い例です。この3値比較関数は、テストされた値のペアごとに1回だけ使用する必要があります。
ほとんどのプラットフォームには、数値や文字列などのさまざまな基本的な型で機能するデフォルトの比較関数があります。
「S」、「M」、「L」、「XL」のTシャツのサイズなど、他のものをソートしたい場合はどうすればよいでしょうか?Tシャツサイズの型でデフォルトの比較関数を実装するか、Tシャツサイズを比較できるもの(数値など)に変換するキー抽出関数を使用するかの2つの方法があります。
複数のキーでソートする必要がある場合、それを行うための大雑把な方法は、すべてのキー比較を1つの比較関数ラムダに組み込むことです。
ruby…["J.C. Bach", "J.S Bach", "C.P.E. Bach", "T Albinoni"].sort do |a,b| first = a.split.last <=> b.split.last (0 != first) ? first : a <=> b end # => ["T Albinoni", "C.P.E. Bach", "J.C. Bach", "J.S Bach"]
しかし、これは明らかに面倒です。より良いアプローチは、キー抽出関数のリストをソートメソッドに渡して、順番に試すことです。
["J.C. Bach", "J.S Bach", "C.P.E. Bach", "T Albinoni"]. sort_by{|s| [s.split.last, s]} # => ["T Albinoni", "C.P.E. Bach", "J.C. Bach", "J.S Bach"]
(sort-by (juxt #(last (clojure.string/split % #"\s+")) identity) ["J.C. Bach" "J.S Bach" "C.P.E. Bach" "T Albinoni"]) ;; => ("T Albinoni" "C.P.E. Bach" "J.C. Bach" "J.S Bach")