sortとsortedの概要
プログラミングをしていると、データを並び替えたい場面によく遭遇します。
例えば、「テストの点数を高い順に並べたい」とか、「動物の名前をあいうえお順に整理したい」といった場合です。
そんなとき活躍するのが、sortメソッドとsorted関数です。どちらも「データを並び替える」という同じ目的で使われますが、実は動作の仕組みや適用場面に明確な違いがあります。
まずは、sortとsortedの基本的な特徴と使い分けの要点についてくわしく見ていきましょう。
【関連】
Pythonをもっと詳しく学ぶならpaizaラーニング
基本仕様の比較
sort()とsorted()の主な違いを整理すると、次のようになります。
項目 |
sort |
sorted |
|---|---|---|
種類 |
リストのメソッド |
組み込み関数 |
返り値 |
None |
新しいリスト |
対象 |
リストのみ |
すべてのイテラブル |
元データの変更 |
あり(破壊的) |
なし(非破壊的) |
sortはリストオブジェクトが持つメソッドで、呼び出すと元のリスト自体を並び替えます。
一方、sortedはあらゆるイテラブルオブジェクト(繰り返し処理できるデータ)を受け取り、新しくソートされたリストを返す関数です。
実際に、コードを見てみましょう。
出力結果
None
['ウサギ', 'キリン', 'ゾウ', 'ライオン']このプログラムでは、animals.sortを実行すると、元のリストが直接並び替えられます。
sort は、リストの並び替えという操作を完了させることだけが目的です。操作が成功したことを示すために、慣習としてNone(何もない)を返します。
2番目のprintでは、並び替えられた後のリストが表示されています。動物の名前が五十音順に並んでいることが確認できるはずです。
破壊的処理の有無
sortとsortedの最も重要な違いは、元のデータを変更するかどうかです。
sortは元のリストを直接変更する「破壊的メソッド」です。一度実行すると、元の順序には戻せません。
一方、sortedは元のデータを保持したまま、新しいソート済みリストを生成する「非破壊的関数」です。
まずsortを使った場合の例を見てみましょう。
出力結果
['ウサギ', 'ゾウ', 'ライオン']このプログラムでは、sortを実行すると元のリストが直接変更されます。元の順序「ライオン、ゾウ、ウサギ」は失われ、「ウサギ、ゾウ、ライオン」という並び順になります。
次にsortedを使った場合を見てみましょう。sortedを使用した場合は元のリストが保持されます。
出力結果
['ライオン', 'ゾウ', 'ウサギ']
['ウサギ', 'ゾウ', 'ライオン']sortedを使うことで元のリストanimalsはそのまま残り、並び替えられた新しいリストがsorted_animalsに格納されます。
元の順序を保持しながら、並び替えた結果も得られるため、「元のデータも後で使いたい」という場合に便利です。
構文の違い
sortとsortedは、書き方が異なります。
sortはリストのメソッドとして呼び出し、sortedは関数として使用します。具体的な書き方を見てみましょう。
出力結果
['ウサギ', 'ゾウ', 'ライオン']
['ウサギ', 'ゾウ', 'ライオン']このプログラムでは、2つの異なる書き方を示しています。
sortはanimals.sort()のように、リストに対して「.(ドット)」でつないで呼び出します。一方、sortedはsorted(animals)のように、関数の括弧の中にリストを入れて呼び出します。どちらも同じパラメータ(keyやreverse)を受け取れますが、返り値の扱い方が大きく異なります。
sortの場合
元のリストそのものを並び替えます。並び替えた結果は元のリストに反映されるので、animals.sort()と書くだけでOKです。わざわざresult = animals.sort()のように結果を変数に入れる必要はありません。入れてもresultにはNoneが入るだけです。
sortedの場合
元のリストは変更せず、並び替えた新しいリストを作って返します。そのため、sorted_animals = sorted(animals)のように、結果を変数に代入して使います。
使い分けの考え方
それでは、sortとsortedをどう使い分けるべきでしょうか?
基本的な選択基準は、元のデータを保持したいかどうかです。元のリストが不要でメモリ効率を重視する場合はsortを使います。元のデータを残して複数のソート結果を作成したい場合はsortedを選びましょう。
出力結果
元のスコア: [85, 92, 78, 96, 88]
上位順: [96, 92, 88, 85, 78]テストの点数をsortedで並び替えています。reverse=Trueを指定することで、高い点数から順に並びます。元のリストscoresは変更されず、並び替えた結果がtop_scoresに格納されています。
ちなみに、リスト以外のデータ型(タプルや文字列)をソートする場合は、必然的にsortedを使用することになります。なぜなら、sortはリスト専用のメソッドで、他のデータ型では使えないからです。
sortの特徴と使い方
sortメソッドは、リストの並び替えをするときに非常に有用な選択肢になります。
このメソッドの最大の特徴は、新しいリストを作らずに、元のリスト自体を直接並び替える点にあります。そのため、余分なメモリを使わずに効率よくソートができるのです。
「元の順序はもう使わない」「とにかく並び替えたい」といった場面では、sortがシンプルで効率的な解決策になります。
それでは、sortの具体的な使い方と、実際にどんな場面で役立つのかを見ていきましょう。
破壊的メソッドとしての性質
sortを実行すると、元のリストの中身が並び替えられます。この動作を「破壊的」と呼びます。
「破壊的」というと物騒な響きですが、これは単に「元のデータを書き換える」という意味です。一度並び替えると、元の順序には戻せません。もし元の順序も後で必要になるかもしれないという場合は、並び替える前にリストのコピーを作っておくと安心です。
実際の例で確認してみましょう。
出力結果
ソート後: ['ウサギ', 'キリン', 'ゾウ', 'ライオン']
元のデータ: ['ライオン', 'ゾウ', 'ウサギ', 'キリン']並び替える前にcopyメソッドで、元のリストをバックアップしています。animals.sortを実行するとanimalsは並び替えられますが、originalには元の順序が残っています。「念のため元の順序も取っておきたい」という場合は、この方法を使いましょう。
なお、sortは戻り値としてNoneを返します。これは「このメソッドは元のオブジェクトを変更する操作です」というPythonのメッセージのようなものです。
reverseの利用
並び替えの方向を逆にしたい場合は、reverse=Trueというパラメータを指定します。
通常、sortは小さい順(昇順)に並べますが、reverse=Trueを付けると大きい順(降順)に並べ替えられます。数値なら大きい値から小さい値へ、文字列なら辞書順の逆順になります。
出力結果
[9, 6, 5, 4, 3, 2, 1, 1]
['ライオン', 'ゾウ', 'ウサギ']数値のリストを大きい順に並び替えていることが確認できますね。
動物の名前のリストも逆順に並び替えています。日本語の場合、Unicode(文字コード)の順序に従って並びます。
何も指定しない場合は小さい順に並ぶので、大きい順にしたいときだけreverse=Trueを使いましょう。
keyによるcustomソート
「普通の順序じゃなくて、独自の基準で並び替えたい」という場面もあります。
そんなときはkeyパラメータを使います。ここに関数を指定すると、その関数の結果を基準に並び替えができるのです。
例えば、「文字列の長さ順に並べたい」という場合を考えてみましょう。通常は辞書順(あいうえお順)で並びますが、key=lenを指定すると文字数を基準にして、並び替えることができます。
出力結果
['ゾウ', 'ウサギ', 'ライオン', 'ハムスター']
['ハムスター', 'ライオン', 'ウサギ', 'ゾウ']最初の例では、文字数が少ない順に並んでいます。2番目の例では、さらにreverse=Trueを追加して、文字数が多い順に並び替えています。
このように、keyパラメータを使うことで、さまざまな基準での並び替えが可能になります。
sortを使うべきケース
どんな場面でsortを使うのが良いのでしょうか?
一番のポイントは「元の順序がもう必要ない」という状況です。メモリを節約したい場合や、処理の流れがシンプルで元の順序を保持する必要がない場合にsortは最適だといえます。
実際の使用例を見てみましょう。
出力結果
トップ3: [96, 94, 92]テストの点数を高い順に並び替え、上位3つを取り出しています。
scoresリスト自体が並び替えられるため、その後[:3]というスライス記法で簡単に上位3つを取得できます。元の点数の順序は必要ないので、sort()を使うのが効率的です。
また、「一度並び替えたら、以降はずっとその順序で使う」という場合もsortが向いています。無駄なメモリを使わず、コードもシンプルに保てます。
sortedの特徴と応用
sorted関数は、Pythonの組み込み関数として提供されている、非常に汎用性の高いソート機能です。
sortメソッドとの大きな違いは、元のデータをそのまま残しながら、新しい並び替え済みのリストを作ってくれる点です。
さらに、リストだけでなく、タプルや文字列など、さまざまなデータ型に対して使える柔軟性も持っています。
データ分析や、元のデータを何度も参照したい場面では、このsortedが大活躍します。それでは、具体的な使い方と活用場面を見ていきましょう。
さまざまなiterableへの適用
sortedの最大の強みは、リスト以外のデータ構造にも使える点です。
タプル、文字列、辞書のキーなど、「繰り返し処理できるもの(イテラブル)」であれば、どんなデータでも並び替えられます。
この柔軟性が、sortメソッドとの大きな違いです。sortはリスト専用ですが、sortedはもっと幅広く対応できるのです。
出力結果
['ウサギ', 'ゾウ', 'ライオン']
['イ', 'オ', 'ラ', 'ン']タプル(変更できないリスト)を並び替えています。タプルにはsortではなく、sortedを使う必要があります。その結果は、新しいリストとして返されます。次に、文字列「ライオン」を一文字ずつに分解して並び替えています。文字列も「繰り返し処理できる」データなので、sortedで処理できます。
辞書の場合も同様です。辞書にsortedを使うとキーが並び替えられ、リストとして返されます。値を基準に並び替えたい場合は、keyパラメータと組み合わせて使います。
非破壊的処理のメリット
元のデータを保持する「非破壊的」な処理により、同じデータから複数の異なるソート結果を得ることができます。これは、データをさまざまな角度から分析したいときや、複数の処理で同じ元データを参照したいときに特に便利です。
実際の例で見てみましょう。
出力結果
元のデータ: ['ライオン', 'ゾウ', 'ウサギ', 'キリン']
昇順: ['ウサギ', 'キリン', 'ゾウ', 'ライオン']
降順: ['ライオン', 'ゾウ', 'キリン', 'ウサギ']元のリストanimalsから、昇順と降順の2つの並び替え結果を作っています。
元のリストは変更されず、そのまま残っています。「元のデータも確認したい」場合や「複数の並び順で比較したい」という場面で、この非破壊的な性質は威力を発揮します。
このように、元データの整合性を保ちながら、さまざまな視点でのデータ分析が可能になるのです。
sortedを使うべき場面
sortedは、関数チェーン(複数の処理を続けて書く方法)や関数型プログラミングとの相性が抜群です。
また、データを変更せずに扱いたい場面では、sorted()が必須の選択肢になります。
実際の使用例を見てみましょう。
出力結果
2より大きい数の上位3つ: [9, 6, 5]この例では、複数の処理を一行でまとめています。
まず[x for x in numbers if x > 2]で2より大きい数を抽出し、それをsortedで降順に並び替え、最後に[:3]で上位3つを取得しています。元のリストnumbersは一切変更されないため、後で別の処理でも使えます。
特にWebアプリケーションでユーザーのデータを扱う場合、元のデータを変更しないsortedを使う方が安全です。こうすることで、うっかり元データを壊してしまったというミスを防げます。
また、デバッグ(バグ探し)のときも、元のデータを確認できる状態で並び替え結果を見られるため、問題の原因を見つけやすくなります。
sortとsortedの速度・時間計算量
Pythonで並び替えをするとき、内部では「Timsort(ティムソート)」という高度なアルゴリズムが動いています。
sortとsortedは、どちらも同じTimsortアルゴリズムを使っているため、基本的な処理速度は同じです。
ただし、メモリの使い方や実際の実行速度には微妙な違いがあります。「大量のデータを扱いたい」ときや「できるだけ高速に処理したい」といった場面では、この違いを理解しておくと役立ちます。
Timsortの概要
Timsortは、マージソートとインサートソートという2つの並び替え手法の良いところを組み合わせたハイブリッドアルゴリズムです。このアルゴリズムの優れている点は、実際のデータでよく見られる「部分的に既に並んでいるデータ」に対して、特に高い性能を発揮することです。
例えば、ほぼ並んでいるデータや、逆順に並んでいるデータを効率的に処理できます。
出力結果
元データ: ['アリ', 'イヌ', 'ウサギ', 'エビ', 'オオカミ', 'カエル']
ソート後: ['アリ', 'イヌ', 'ウサギ', 'エビ', 'オオカミ', 'カエル']元のデータが既に五十音順に並んでいます。Timsortは、このような既に並んでいる状態を素早く認識し、無駄な処理をスキップします。
既にソート済みのデータや逆順のデータに対しては、最良の場合O(n)という線形時間(データ量に比例する時間)で処理が完了します。これは非常に高速です。
時間計算量については、次の項でくわしく説明します。
時間計算量(time complexity)について
アルゴリズムの性能を表す「時間計算量」を理解しておくと、データ量が増えたときの処理時間を予測できます。
sortとsortedの時間計算量は次のようになります。
ケース |
計算量 |
説明 |
|---|---|---|
最良 |
O(n) |
既にソート済みの場合 |
平均 |
O(n log n) |
一般的なランダムデータ |
最悪 |
O(n log n) |
逆順など最も処理が重い場合 |
時間計算量における「O(n)」や「O(n log n)」といった表現は、処理時間が増えるペースをシンプルな記号で表したものです。この記号(O:オーダー)の後の括弧内が、データ量nの増え方に比べて、時間がどれだけ増えるかを示しています。
例えば、O(n)は「データ量nに時間が比例して増える」という意味で、非常に高速な処理であることを表します。
この表を見ると、Timsortの優秀さがわかります。
一般的なクイックソートという並び替え手法では、最悪の場合O(n²)という非常に遅い処理になってしまうことがあります。しかし、Timsortは最悪の場合でもO(n log n)を保証してくれます。
つまり、どんなデータが来ても安定した速度で処理できるということです。大量のデータを扱う場合でも、予測可能な性能を提供してくれるため、安心して使えます。
出力結果(例)
10000要素のソート時間: 0.000039秒※出力結果は実行ごとに異なります
このプログラムは、10000個の数値(逆順)を並び替える時間を測定しています。実際に実行すると、Timsortのソート時間を確認することができます。
sortとsortedの速度傾向
sortは元のリストを直接変更するため、新しいメモリ領域を確保する必要がありません。
一方、sortedは新しいリストを作成するため、その分のメモリ確保が必要です。そのため、わずかながら処理時間が長くなる傾向があります。
出力結果
sort後のメモリ位置変更: Falseid関数を使ってリストのメモリ上の位置を確認しています。
sortの前後でidが変わっていない(False)ことから、同じメモリ領域を使い続けていることがわかります。つまり、新しくメモリを確保していないということです。
ただし、実際の速度差は非常に小さく、普通のアプリケーションでは体感できるレベルではありません。むしろ、コードの読みやすさや保守のしやすさを重視して選ぶ方が重要だということは認識しておきましょう。
パフォーマンスを意識した使い分け
実際の開発では、次のような基準でパフォーマンスを考慮した選択を行います。
メモリに制約がある環境ではsortを選びますが、データの再利用性を重視する場合はsortedを選択するのが一般的です。
出力結果
高得点者: [96, 94, 92, 91, 88, 85]関数の戻り値として並び替え結果を返す場面でsortedを使っています。元のリストscoresは変更されないため、呼び出し側で安心して使えます。
メモリ使用量が重要な場合や、一度きりの処理ではsortを選びます。一方、関数の戻り値として使う場合や、複数の処理で元データを参照する場合はsortedを選びましょう。
このように、状況に応じて適切に使い分けることが大切です。
よくある質問(Q&A)
Q: sort()の戻り値をそのまま使えないのはなぜ?
A: sort()は元のリストを変更する破壊的メソッドのため、戻り値はNoneです。これはPythonの設計思想で、オブジェクト自体を変更する操作と新しいオブジェクトを返す操作を明確に区別しています。
出力結果
None
['ウサギ', 'ゾウ']Q: 文字列をソートすると文字化けする?
A: 文字化けではなく、Pythonの文字列比較ルールに基づいた結果です。ひらがなとカタカナが混在する場合、Unicodeの順序で並び替えられます。
出力結果
['あいうえお', 'さしすせそ', 'カキクケコ']Q: 数値と文字列が混在するリストはソートできる?
A: Python 3では型が異なる要素の比較はエラーになります。事前にすべて同じ型に変換するか、keyパラメータで統一した比較基準を設定する必要があります。
出力結果
['1', 2, 3, '4']Q: 辞書をソートする最も簡単な方法は?
A: 辞書のキーでソートする場合はsorted()に辞書を渡し、値でソートする場合はkeyパラメータにlambdaを指定します。
出力結果
[('ウサギ', 2), ('ライオン', 190), ('ゾウ', 5000)]Q: ソートの安定性とは何ですか?
A: 同じ値を持つ要素の相対位置が、ソート後も保持される性質です。Pythonのソートは安定ソートなので、この特性を利用した多段階ソートが可能です。
出力結果
[('ウサギ', 2), ('ライオン', 190), ('トラ', 190), ('ゾウ', 5000)]まとめ
この記事では、Pythonにおけるsortメソッドとsorted関数の違いについて、基本的な仕組みから実践的な使い分けまで詳しく解説してきました。
sortとsortedを適切に使い分けることで、より効率的で保守性の高いプログラムを作成できます。
sortとsortedが活躍する場面について確認しておきましょう。
sortが活躍する場面
- 並び替えで元のデータが必要ない場合
- 大量データを一度きり処理したいとき
- メモリ使用量を節約したいとき
sortedが活躍する場面
- 並び替えで元のデータを保持したい場合
- リスト以外のデータ(タプルや文字列)を並び替えたいとき
- 関数の戻り値として並び替え結果を返したいとき
sortとsortedを使う上で、押さえておきたいポイントは次の通りです。
重要なポイント
- sortは戻り値としてNoneを返す
- 元のデータを残したい場合はcopyメソッドで事前にバックアップを作成する
- reverse=Trueパラメータで降順(大きい順)に並び替えできる
- keyパラメータに関数を指定することで、独自の基準でソートできる
- どちらもTimsortアルゴリズムを採用し、最悪の場合でも安定した性能を保証する
初めてsortとsortedを学ぶ方も、この記事で紹介した基本的な違いと実用例を参考に、実際にコードを書いてみてください。
sortやsortedの特性を理解できると、データの性質や処理要件に応じた最適なプログラミングができるようになります。
特に、リストやソートの概念はプログラミングの根幹に関わる重要な概念です。ぜひマスターして、一歩ずつ確実にプログラミングスキルを身に付けていきましょう。