Pythonでsorted()およびsort()を使用する方法
すべてのプログラマは、ある時点でアイテムまたはデータをソートするコードを作成する必要があります。 並べ替えは、ユーザーの最新のアクティビティをタイムスタンプで並べ替える場合でも、メール受信者のリストを姓のアルファベット順に並べる場合でも、アプリケーションのユーザーエクスペリエンスにとって重要です。 Pythonの並べ替え機能は、基本的な並べ替えを実行したり、詳細なレベルで順序をカスタマイズしたりするための堅牢な機能を提供します。
このガイドでは、さまざまなデータ構造のさまざまな種類のデータを並べ替える方法、順序をカスタマイズする方法、およびPythonで2つの異なる並べ替え方法を操作する方法を学習します。
このチュートリアルを終了すると、次の方法がわかります。
-
データ構造に基本的なPythonの並べ替えと順序付けを実装する
-
sorted()
と.sort()
を区別する -
固有の要件に基づいてコード内の複雑なソート順をカスタマイズします
このチュートリアルでは、lists and tuplesとsetsの基本を理解する必要があります。 これらのデータ構造はこのチュートリアルで使用され、いくつかの基本的な操作が実行されます。 また、このチュートリアルではPython 3を使用しているため、Python 2を使用している場合、このチュートリアルの出力例は若干異なる場合があります。
Free Bonus:Click here to get access to a chapter from Python Tricks: The Bookは、Pythonのベストプラクティスと、より美しい+ Pythonicコードをすぐに適用できる簡単な例を示しています。
sorted()
を使用した値の順序付け
Pythonの並べ替えを開始するには、まず数値データと文字列データの両方を並べ替える方法を確認します。
番号の並べ替え
Pythonを使用して、sorted()
を使用してリストを並べ替えることができます。 この例では、整数のリストが定義されてから、numbers
変数を引数としてsorted()
が呼び出されます。
>>>
>>> numbers = [6, 9, 3, 1]
>>> sorted(numbers)
[1, 3, 6, 9]
>>> numbers
[6, 9, 3, 1]
このコードからの出力は、新しいソートされたリストです。 元の変数が出力されると、初期値は変更されません。
この例は、sorted()
の4つの重要な特性を示しています。
-
関数
sorted()
を定義する必要はありませんでした。 Pythonの標準インストールで利用可能な組み込み関数です。 -
sorted()
は、追加の引数やパラメーターなしで、numbers
の値を昇順、つまり最小から最大の順に並べています。 -
sorted()
はソートされた出力を提供し、元の値を変更しないため、元のnumbers
変数は変更されません。 -
sorted()
が呼び出されると、戻り値として順序付きリストが提供されます。
この最後のポイントは、sorted()
をリストで使用でき、出力をすぐに変数に割り当てることができることを意味します。
>>>
>>> numbers = [6, 9, 3, 1]
>>> numbers_sorted = sorted(numbers)
>>> numbers_sorted
[1, 3, 6, 9]
>>> numbers
[6, 9, 3, 1]
この例では、sorted()
の出力を格納する新しい変数numbers_sorted
があります。
sorted()
でhelp()
を呼び出すことにより、これらすべての観測を確認できます。 オプションの引数key
およびreverse
については、チュートリアルの後半で説明します。
>>>
>>> # Python 3
>>> help(sorted)
Help on built-in function sorted in module builtins:
sorted(iterable, /, *, key=None, reverse=False)
Return a new list containing all items from the iterable in ascending order.
A custom key function can be supplied to customize the sort order, and the
reverse flag can be set to request the result in descending order.
Technical Detail: Python 2から移行していて、同じ名前の機能に精通している場合は、Python3のいくつかの重要な変更点に注意する必要があります。
-
Python 3の
sorted()
にはcmp
パラメータがありません。 代わりに、key
のみがカスタムソートロジックの導入に使用されます。 -
key
とreverse
は、位置引数として渡すことができるPython 2とは異なり、キーワード引数として渡す必要があります。
Python 2のcmp
関数をkey
関数に変換する必要がある場合は、functools.cmp_to_key()
を確認してください。 このチュートリアルでは、Python 2を使用した例を取り上げません。
sorted()
は、タプルとセットで非常によく似た方法で使用できます。
>>>
>>> numbers_tuple = (6, 9, 3, 1)
>>> numbers_set = {5, 5, 10, 1, 0}
>>> numbers_tuple_sorted = sorted(numbers_tuple)
>>> numbers_set_sorted = sorted(numbers_set)
>>> numbers_tuple_sorted
[1, 3, 6, 9]
>>> numbers_set_sorted
[0, 1, 5, 10]
入力がセットとタプルであったとしても、sorted()
は定義により新しいリストを返すため、出力がリストであることに注意してください。 返されたオブジェクトは、入力タイプと一致する必要がある場合、新しいタイプにキャストできます。 定義によるセットは順序付けられていないため、結果のリストをセットにキャストしようとする場合は注意してください。
>>>
>>> numbers_tuple = (6, 9, 3, 1)
>>> numbers_set = {5, 5, 10, 1, 0}
>>> numbers_tuple_sorted = sorted(numbers_tuple)
>>> numbers_set_sorted = sorted(numbers_set)
>>> numbers_tuple_sorted
[1, 3, 6, 9]
>>> numbers_set_sorted
[0, 1, 5, 10]
>>> tuple(numbers_tuple_sorted)
(1, 3, 6, 9)
>>> set(numbers_set_sorted)
{0, 1, 10, 5}
set
にキャストされたときのnumbers_set_sorted
値は、期待どおりに順序付けられていません。 もう1つの変数numbers_tuple_sorted
は、ソートされた順序を保持していました。
文字列の並べ替え
str
型は、リストやタプルなどの他の反復可能オブジェクトと同様にソートされます。 以下の例は、sorted()
が渡された値の各文字を反復処理し、出力でそれらを順序付ける方法を示しています。
>>>
>>> string_number_value = '34521'
>>> string_value = 'I like to sort'
>>> sorted_string_number = sorted(string_number_value)
>>> sorted_string = sorted(string_value)
>>> sorted_string_number
['1', '2', '3', '4', '5']
>>> sorted_string
[' ', ' ', ' ', 'I', 'e', 'i', 'k', 'l', 'o', 'o', 'r', 's', 't', 't']
sorted()
は、str
をリストのように扱い、各要素を反復処理します。 str
では、各要素はstr
の各文字を意味します。 sorted()
は文を異なる方法で処理せず、スペースを含む各文字をソートします。
.split()
はこの動作を変更して出力をクリーンアップでき、.join()
はすべてを元に戻すことができます。 出力の特定の順序と、その理由がすぐに説明されます。
>>>
>>> string_value = 'I like to sort'
>>> sorted_string = sorted(string_value.split())
>>> sorted_string
['I', 'like', 'sort', 'to']
>>> ' '.join(sorted_string)
'I like sort to'
この例の元の文は、str
のままにするのではなく、単語のリストに変換されます。 次に、そのリストがソートおよび結合されて、リストの代わりに再びstr
が形成されます。
Pythonソートの制限事項と落とし穴
Pythonを使用して整数以外の値を並べ替えるときに発生する可能性のある制限と奇妙な動作に注意する価値があります。
比較できないデータ型のリストをsorted()
にすることはできません
違いが大きすぎるため、sorted()
だけでは比較できないデータ型があります。 比較できないデータを含むリストでsorted()
を使用しようとすると、Pythonはエラーを返します。 この例では、同じリスト内のNone
とint
は、互換性がないため、並べ替えることができません。
>>>
>>> mixed_types = [None, 0]
>>> sorted(mixed_types)
Traceback (most recent call last):
File "", line 1, in
TypeError: '<' not supported between instances of 'int' and 'NoneType'
このエラーは、与えられた値をPythonがソートできない理由を示しています。 less演算子(<
)を使用して値を並べ替え、並べ替え順で低い値を判別しようとしています。 2つの値を手動で比較することにより、このエラーを再現できます。
>>>
>>> None < 0
Traceback (most recent call last):
File "", line 1, in
TypeError: '<' not supported between instances of 'NoneType' and 'int'
sorted()
を使用せずに2つの比較できない値を比較しようとすると、同じTypeError
がスローされます。
リスト内の値を比較でき、TypeError
がスローされない場合は、リストを並べ替えることができます。 これにより、本質的に順序付け不可能な値でイテラブルがソートされ、意味のない出力が生成されるのを防ぎます。
たとえば、1
の数は、apple
の単語の前に置く必要がありますか? ただし、すべてが数字である整数と文字列の組み合わせがイテラブルに含まれる場合、リスト内包表記を使用して、同等のデータ型にキャストできます。
>>>
>>> mixed_numbers = [5, "1", 100, "34"]
>>> sorted(mixed_numbers)
Traceback (most recent call last):
File "", line 1, in
TypeError: '<' not supported between instances of 'str' and 'int'
>>> # List comprehension to convert all values to integers
>>> [int(x) for x in mixed_numbers]
[5, 1, 100, 34]
>>> sorted([int(x) for x in mixed_numbers])
[1, 5, 34, 100]
mixed_numbers
の各要素には、str
値をint
値に変換するために呼び出されるint()
があります。 次に、sorted()
が呼び出され、各要素を正常に比較して、ソートされた出力を提供できます。
Pythonは、値を暗黙的に別の型に変換することもできます。 以下の例では、1 <= 0
の評価は誤ったステートメントであるため、評価の出力はFalse
になります。 数値1
はbool
タイプとしてTrue
に変換でき、0
はFalse
に変換されます。
リスト内の要素は異なって見えますが、それらはすべてブール値(True
またはFalse
)に変換され、sorted()
を使用して相互に比較できます。
>>>
>>> similar_values = [False, 0, 1, 'A' == 'B', 1 <= 0]
>>> sorted(similar_values)
[False, 0, False, False, 1]
'A' == 'B'
と1 <= 0
はFalse
に変換され、順序付けられた出力で返されます。
この例は、ソートの重要な側面を示しています:sort stability。 Pythonでは、等しい値を並べ替えると、出力の元の順序が保持されます。 1
が移動した場合でも、他のすべての値は等しいため、相互に関連する元の順序を保持します。 以下の例では、すべての値は等しいと見なされ、元の位置を保持します。
>>>
>>> false_values = [False, 0, 0, 1 == 2, 0, False, False]
>>> sorted(false_values)
[False, 0, 0, False, 0, False, False]
元の順序と並べ替えられた出力を調べると、1 == 2
がFalse
に変換され、並べ替えられたすべての出力が元の順序になっていることがわかります。
文字列を並べ替えるとき、大事なこと
sorted()
を文字列のリストで使用して、値を昇順で並べ替えることができます。これは、デフォルトではアルファベット順に表示されます。
>>>
>>> names = ['Harry', 'Suzy', 'Al', 'Mark']
>>> sorted(names)
['Al', 'Harry', 'Mark', 'Suzy']
ただし、Pythonは、各文字列の最初の文字のUnicode Code Pointを使用して、昇順の並べ替え順序を決定しています。 これは、sorted()
がAl
とal
の名前を同じように扱わないことを意味します。 この例では、ord()
を使用して、各文字列の最初の文字のUnicodeコードポイントを返します。
>>>
>>> names_with_case = ['harry', 'Suzy', 'al', 'Mark']
>>> sorted(names_with_case)
['Mark', 'Suzy', 'al', 'harry']
>>> # List comprehension for Unicode Code Point of first letter in each word
>>> [(ord(name[0]), name[0]) for name in sorted(names_with_case)]
[(77, 'M'), (83, 'S'), (97, 'a'), (104, 'h')]
name[0]
はsorted(names_with_case)
の各要素の最初の文字を返し、ord()
はUnicodeコードポイントを提供します。 アルファベットではa
がM
の前にありますが、M
のコードポイントはa
の前にあるため、ソートされた出力の最初にM
があります。
最初の文字が同じ場合、sorted()
は2番目の文字を使用して順序を決定し、同じ場合は3番目の文字を使用し、以下同様に文字列の最後まで続きます。
>>>
>>> very_similar_strs = ['hhhhhd', 'hhhhha', 'hhhhhc','hhhhhb']
>>> sorted(very_similar_strs)
['hhhhha', 'hhhhhb', 'hhhhhc', 'hhhhhd']
very_similar_strs
の各値は、最後の文字を除いて同じです。 sorted()
は文字列を比較し、最初の5文字が同じであるため、出力は6番目の文字に基づきます。
同一の値を含む文字列は、短い文字列が長い文字列と比較する要素を持たないため、最短から最長にソートされます。
>>>
>>> different_lengths = ['hhhh', 'hh', 'hhhhh','h']
>>> sorted(different_lengths)
['h', 'hh', 'hhhh', 'hhhhh']
最短の文字列h
が最初に並べられ、最長の文字列hhhhh
が最後に並べられます。
reverse
引数でsorted()
を使用する
sorted()
のhelp()
ドキュメントに示されているように、reverse
と呼ばれるオプションのキーワード引数があり、割り当てられたブール値に基づいて並べ替え動作を変更します。 reverse
にTrue
が割り当てられている場合、並べ替えは降順で行われます。
>>>
>>> names = ['Harry', 'Suzy', 'Al', 'Mark']
>>> sorted(names)
['Al', 'Harry', 'Mark', 'Suzy']
>>> sorted(names, reverse=True)
['Suzy', 'Mark', 'Harry', 'Al']
ソートのロジックは同じままです。つまり、名前はまだ最初の文字でソートされています。 ただし、reverse
キーワードをTrue
に設定すると、出力が逆になります。
False
が割り当てられると、順序は昇順のままになります。 前の例のいずれかを使用して、True
またはFalse
の両方を使用したリバースの動作を確認できます。
>>>
>>> names_with_case = ['harry', 'Suzy', 'al', 'Mark']
>>> sorted(names_with_case, reverse=True)
['harry', 'al', 'Suzy', 'Mark']
>>> similar_values = [False, 1, 'A' == 'B', 1 <= 0]
>>> sorted(similar_values, reverse=True)
[1, False, False, False]
>>> numbers = [6, 9, 3, 1]
>>> sorted(numbers, reverse=False)
[1, 3, 6, 9]
sorted()
とkey
引数
sorted()
の最も強力なコンポーネントの1つは、key
と呼ばれるキーワード引数です。 この引数は関数が渡されることを想定しており、その関数はソートされるリストの各値で使用され、結果の順序を決定します。
基本的な例を示すために、特定のリストを順序付けるための要件は、リスト内の文字列の長さであり、最短から最長であると仮定しましょう。 文字列の長さを返す関数len()
は、key
引数とともに使用されます。
>>>
>>> word = 'paper'
>>> len(word)
5
>>> words = ['banana', 'pie', 'Washington', 'book']
>>> sorted(words, key=len)
['pie', 'book', 'banana', 'Washington']
結果の順序は、文字列の順序が最短から最長のリストです。 リスト内の各要素の長さはlen()
によって決定され、昇順で返されます。
大文字と小文字が異なる場合、最初の文字でソートする前の例に戻りましょう。 key
は、文字列全体を小文字に変換することで、この問題を解決するために使用できます。
>>>
>>> names_with_case = ['harry', 'Suzy', 'al', 'Mark']
>>> sorted(names_with_case)
['Mark', 'Suzy', 'al', 'harry']
>>> sorted(names_with_case, key=str.lower)
['al', 'harry', 'Mark', 'Suzy']
key
は元のリストのデータを操作しないため、出力値は小文字に変換されていません。 並べ替え中に、key
に渡された関数が各要素で呼び出されて並べ替え順序が決定されますが、元の値が出力に含まれます。
key
引数を持つ関数を使用する場合、2つの主な制限があります。
まず、key
に渡される関数で必要な引数の数は1でなければなりません。
以下の例は、2つの引数を取る加算関数の定義を示しています。 その関数が数値リストのkey
で使用されている場合、2番目の引数が欠落しているため、失敗します。 ソート中にadd()
が呼び出されるたびに、リストから一度に1つの要素のみを受け取ります。
>>>
>>> def add(x, y):
... return x + y
...
>>> values_to_add = [1, 2, 3]
>>> sorted(values_to_add, key=add)
Traceback (most recent call last):
File "", line 1, in
TypeError: add() missing 1 required positional argument: 'y'
2番目の制限は、key
で使用される関数が、反復可能オブジェクト内のすべての値を処理できる必要があることです。 たとえば、sorted()
で使用される文字列として表される数値のリストがあり、key
はint
を使用してそれらを数値に変換しようとしています。 iterableの値を整数にキャストできない場合、関数は失敗します:
>>>
>>> values_to_cast = ['1', '2', '3', 'four']
>>> sorted(values_to_cast, key=int)
Traceback (most recent call last):
File "", line 1, in
ValueError: invalid literal for int() with base 10: 'four'
str
としての各数値はint
に変換できますが、four
は変換できません。 これにより、ValueError
が発生し、four
は無効であるため、int
に変換できないことを説明します。
key
機能は非常に強力です。これは、組み込み関数またはユーザー定義関数を問わず、ほとんどすべての関数を使用して出力順序を操作できるためです。
順序付けの要件が各文字列の最後の文字で反復可能を順序付けることである場合(および文字が同じである場合は次の文字を使用するため)、functionを定義して、並べ替えに使用できます。 以下の例では、渡された文字列を逆にする関数を定義し、その関数をkey
の引数として使用します。
>>>
>>> def reverse_word(word):
... return word[::-1]
...
>>> words = ['banana', 'pie', 'Washington', 'book']
>>> sorted(words, key=reverse_word)
['banana', 'pie', 'book', 'Washington']
word[::-1]
スライス構文は、文字列を逆にするために使用されます。 各要素にはreverse_word()
が適用され、並べ替え順序は逆方向の単語の文字に基づきます。
スタンドアロン関数を作成する代わりに、key
引数で定義されたlambda
関数を使用できます。
lambda
は、次のような無名関数です。
-
インラインで定義する必要があります
-
名前がない
-
statementsを含めることはできません
-
関数のように実行されます
以下の例では、key
は名前のないlambda
として定義され、lambda
がとる引数はx
であり、x[::-1]
は演算です。これは引数に対して実行されます:
>>>
>>> words = ['banana', 'pie', 'Washington', 'book']
>>> sorted(words, key=lambda x: x[::-1])
['banana', 'pie', 'book', 'Washington']
x[::-1]
は各要素で呼び出され、単語を逆にします。 その逆の出力はソートに使用されますが、元の単語は引き続き返されます。
要件が変更され、順序も逆にする必要がある場合は、reverse
キーワードをkey
引数と一緒に使用できます。
>>>
>>> words = ['banana', 'pie', 'Washington', 'book']
>>> sorted(words, key=lambda x: x[::-1], reverse=True)
['Washington', 'book', 'pie', 'banana']
lambda
関数は、プロパティに基づいてclass
オブジェクトを並べ替える必要がある場合にも役立ちます。 学生のグループがあり、最終成績で最高から最低まで並べ替える必要がある場合は、lambda
を使用してclass
からgrade
プロパティを取得できます。
>>>
>>> from collections import namedtuple
>>> StudentFinal = namedtuple('StudentFinal', 'name grade')
>>> bill = StudentFinal('Bill', 90)
>>> patty = StudentFinal('Patty', 94)
>>> bart = StudentFinal('Bart', 89)
>>> students = [bill, patty, bart]
>>> sorted(students, key=lambda x: getattr(x, 'grade'), reverse=True)
[StudentFinal(name='Patty', grade=94), StudentFinal(name='Bill', grade=90), StudentFinal(name='Bart', grade=89)]
この例では、namedtuple
を使用して、name
およびgrade
属性を持つクラスを生成します。 lambda
は、各要素でgetattr()
を呼び出し、grade
の値を返します。
reverse
をTrue
に設定すると、昇順の出力が反転して降順になり、最高のグレードが最初に並べられます。
sorted()
でkey
とreverse
の両方のキーワード引数を利用する場合、順序付けを行う方法は無限にあります。 小さな関数に基本的なlambda
を使用する場合、コードをクリーンで短く保つことができます。または、まったく新しい関数を記述してインポートし、key引数で使用することもできます。
.sort()
を使用した値の順序付け
非常によく似た名前の.sort()
は、組み込みのsorted()
とはかなり異なります。 それらは多かれ少なかれ同じことを達成しますが、list.sort()
のhelp()
のドキュメントは、.sort()
とsorted()
の2つの最も重要な違いを強調しています。
>>>
>>> # Python2
Help on method_descriptor:
sort(...)
L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;
cmp(x, y) -> -1, 0, 1
>>> # Python3
>>> help(list.sort)
Help on method_descriptor:
sort(...)
L.sort(key=None, reverse=False) -> None -- stable sort *IN PLACE*
まず、sortはlist
クラスのメソッドであり、リストでのみ使用できます。 iterableが渡されるビルトインではありません。
次に、.sort()
はNone
を返し、その場で値を変更します。 コードのこれらの違いの両方の影響を見てみましょう。
>>>
>>> values_to_sort = [5, 2, 6, 1]
>>> # Try to call .sort() like sorted()
>>> sort(values_to_sort)
Traceback (most recent call last):
File "", line 1, in
NameError: name 'sort' is not defined
>>> # Try to use .sort() on a tuple
>>> tuple_val = (5, 1, 3, 5)
>>> tuple_val.sort()
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'tuple' object has no attribute 'sort'
>>> # Sort the list and assign to new variable
>>> sorted_values = values_to_sort.sort()
>>> print(sorted_values)
None
>>> # Print original variable
>>> print(values_to_sort)
[1, 2, 5, 6]
このコード例では、sorted()
と比較して.sort()
の動作にかなり劇的な違いがあります。
-
.sort()
の順序付けられた出力はないため、新しい変数への割り当てはNone
タイプのみを渡します。 -
values_to_sort
リストはその場で変更されており、元の順序はまったく維持されていません。
これらの動作の違いにより、.sort()
とsorted()
はコード内で完全に互換性がなくなり、間違った方法で使用すると、予期しない結果が生じる可能性があります。
.sort()
には、sorted()
と同じ堅牢な機能を生成する同じkey
およびreverse
オプションのキーワード引数があります。 ここでは、フレーズのリストを3番目の単語の2番目の文字でソートし、リストを逆順に返すことができます。
>>>
>>> phrases = ['when in rome',
... 'what goes around comes around',
... 'all is fair in love and war'
... ]
>>> phrases.sort(key=lambda x: x.split()[2][1], reverse=True)
>>> phrases
['what goes around comes around', 'when in rome', 'all is fair in love and war']
このサンプルでは、lambda
を使用して次のことを行います。
-
各フレーズを単語のリストに分割します
-
3番目の要素、この場合は単語を見つける
-
その単語の2番目の文字を見つける
sorted()
を使用する場合と.sort()
を使用する場合
sorted()
と.sort()
の違いを見てきましたが、どちらをいつ使用しますか?
5kのレースが近づいているとしましょう:The First Annual Python 5k。 レースのデータをキャプチャして並べ替える必要があります。 キャプチャする必要があるデータは、ランナーのゼッケン番号とレースを終了するのにかかった秒数です。
>>>
>>> from collections import namedtuple
>>> Runner = namedtuple('Runner', 'bibnumber duration')
ランナーがフィニッシュラインを通過すると、各Runner
がrunners
というリストに追加されます。 5kレースでは、すべてのランナーが同時にスタートラインを通過するわけではないため、フィニッシュラインを最初に通過する人が実際には最速の人ではない場合があります。
>>>
>>> runners = []
>>> runners.append(Runner('2528567', 1500))
>>> runners.append(Runner('7575234', 1420))
>>> runners.append(Runner('2666234', 1600))
>>> runners.append(Runner('2425234', 1490))
>>> runners.append(Runner('1235234', 1620))
>>> # Thousands and Thousands of entries later...
>>> runners.append(Runner('2526674', 1906))
ランナーがフィニッシュラインを通過するたびに、ゼッケン番号と秒単位の合計時間がrunners
に追加されます。
現在、結果データの処理を担当する忠実なプログラマーはこのリストを見て、上位5位までの参加者が賞品を獲得した勝者であり、残りのランナーは最速時間でソートされることを知っています。
さまざまな属性による複数の種類のソートの要件はありません。 リストは妥当なサイズです。 リストをどこかに保存することについての言及はありません。 期間で並べ替えて、期間が最も短い5人の参加者を取得します。
>>>
>>> runners.sort(key=lambda x: getattr(x, 'duration'))
>>> top_five_runners = runners[:5]
プログラマーは、key
引数でlambda
を使用して、各ランナーからduration
属性を取得し、.sort()
を使用してrunners
を所定の位置にソートすることを選択します。 runners
がソートされた後、最初の5つの要素がtop_five_runners
に格納されます。
任務完了! レースディレクターがやって来て、Pythonの現在のリリースが3.7であるため、フィニッシュラインを通過した37人ごとに無料のジムバッグを手に入れることを決定したことをプログラマに通知します。
この時点で、ランナーのリストが不可逆的に変更されたため、プログラマーは汗をかき始めます。 ランナーの元のリストを完了した順序で回復し、37人ごとに見つける方法はありません。
重要なデータを処理していて、元のデータを復元する必要がある可能性がほとんどない場合は、.sort()
は最適なオプションではありません。 データがコピーである場合、重要でない作業データである場合、データを取得できるためにデータを失ってもかまわない場合は、.sort()
が適切なオプションになります。
または、sorted()
を使用して同じlambda
を使用してランナーを並べ替えることもできます。
>>>
>>> runners_by_duration = sorted(runners, key=lambda x: getattr(x, 'duration'))
>>> top_five_runners = runners_by_duration[:5]
sorted()
を使用したこのシナリオでは、ランナーの元のリストはそのままで、上書きされていません。 37人ごとにフィニッシュラインを越える必要があるという即席の要件は、元の値と対話することで実現できます。
>>>
>>> every_thirtyseventh_runners = runners[::37]
every_thirtyseventh_runners
は、runners
のリストスライス構文でストライドを使用して作成されます。これには、ランナーがフィニッシュラインを通過した元の順序が含まれています。
Pythonでのソート方法:結論
.sort()
とsorted()
は、reverse
とkey
のオプションのキーワード引数の両方で適切に使用すれば、必要な並べ替え順序を正確に提供できます。
出力とインプレース変更に関しては、どちらも非常に異なる特性を持っているため、データを取り返しのつかないほど上書きする可能性があるため、.sort()
を使用するアプリケーション機能またはプログラムをよく検討してください。
並べ替えの課題を探している熱心なPythonの人のために、並べ替えでより複雑なデータ型を使用してみてください:ネストされたイテラブル。 また、組み込みのオープンソースPythonコード実装に飛び込んで、Timsortと呼ばれるPythonで使用されるソートアルゴリズムについて読んでください。