溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python中sorted與sort用法

發(fā)布時間:2020-09-24 11:31:16 來源:億速云 閱讀:146 作者:Leah 欄目:編程語言

這篇文章將為大家詳細講解有關Python中sorted與sort用法,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

使用sorted()排序值

開始使用Python排序,首先要了解如何對數(shù)字數(shù)據(jù)和字符串數(shù)據(jù)進行排序。

1. 排序數(shù)字型數(shù)據(jù)

可以使用Python通過sorted()對列表進行排序。比如定義了一個整數(shù)列表,然后使用numbers變量作為參數(shù)調(diào)用sorted():

>>> numbers = [6, 9, 3, 1]
>>> sorted(numbers)
[1, 3, 6, 9]
>>> numbers
[6, 9, 3, 1]

輸出是一個新的排序列表,如果打印原始變量時, 原始數(shù)字變量numbers未改變,因為sorted()只提供已排序的輸出,而不會更改原始值。這 意味著sorted()可以在列表中使用,將輸出立即分配給變量:

>>> numbers = [6, 9, 3, 1]
>>> numbers_sorted = sorted(numbers)
>>> numbers_sorted
[1, 3, 6, 9]
>>> numbers
[6, 9, 3, 1]

我們還可以通過調(diào)用sorted的help()來確認所有這些觀察結果??蛇x參數(shù)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.

像操作列表一樣,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()按定義返回一個新列表。如果需要匹配輸入類型,則可以將返回的對象強制轉(zhuǎn)換為新類型。如果嘗試將結果列表強制轉(zhuǎn)換回集合,結果將是無序的,因為集合是無序的,如下:

>>> 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}

2. 排序字符串型數(shù)據(jù)

字符串類型與其他可迭代對象類似,如列表和元組。下面的示例顯示了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()將字符串視為列表并遍歷每個元素。在字符串中,每個元素表示字符串中的一個字符,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'

Python排序的局限性和陷阱

當使用Python對整數(shù)值進行排序時,可能會出現(xiàn)一些限制和奇怪的現(xiàn)象。

1. 具有不能比較數(shù)據(jù)類型的列表無法進行排序

有些數(shù)據(jù)類型使用sorted是無法進行比較的,因為它們的類型不同。如果嘗試在包含不可比較數(shù)據(jù)的列表上使用sorted(),Python將返回錯誤。在此示例中,由于不兼容性,無法對同一列表中的None和int進行排序:

>>> mixed_types = [None, 0]
>>> sorted(mixed_types)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'int' and 'NoneType'

此錯誤顯示了為什么Python無法對給定的值進行排序。它試圖通過使用小于運算符(<)來確定值,以確定排序順序中哪個值較低。 例如,數(shù)字1應該出現(xiàn)在蘋果這個詞之前嗎?但是,如果迭代器包含所有數(shù)字的整數(shù)和字符串的組合,則可以使用列表推導將它們強制轉(zhuǎn)換為可比較的數(shù)據(jù)類型:

>>> mixed_numbers = [5, "1", 100, "34"]
>>> sorted(mixed_numbers)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
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中的每個元素都調(diào)用了int()來將任何str值轉(zhuǎn)換為int值。然后調(diào)用sorted()并成功比較每個元素并提供排序的輸出。

另外,Python還可以隱式地將值轉(zhuǎn)換為另一種類型。在下面的示例中,1 <= 0的評估是false語句,因此評估的輸出將為False。數(shù)字1可以轉(zhuǎn)換為True作為bool類型,而0轉(zhuǎn)換為False。

即使列表中的元素看起來不同,它們也可以全部轉(zhuǎn)換為布爾值(True或False)并使用sorted()進行相互比較:

>>> similar_values = [False, 0, 1, 'A' == 'B', 1 <= 0]
>>> sorted(similar_values)
[False, 0, False, False, 1]

'A'=='B'和1 <= 0轉(zhuǎn)換為False并在有序輸出中返回。

此示例說明了排序的一個重要方面: 排序穩(wěn)定性。 在Python中,當你對相等的值進行排序時,它們將在輸出中保留其原始順序。即使1移動,所有其他值都相等,它們保持相對于彼此的原始順序。在下面的示例中,所有值都被視為相等,并將保留其原始位置:

>>> false_values = [False, 0, 0, 1 == 2, 0, False, False]
>>> sorted(false_values)
[False, 0, 0, False, 0, False, False]

如果檢查原始順序和排序輸出,可以看到1 == 2轉(zhuǎn)換為False,所有排序輸出都是原始順序。

2. 當排序字符串時,大小寫很重要

sorted()可用于字符串列表,以按升序?qū)χ颠M行排序,默認情況下按字母順序排列:

>>> names = ['Harry', 'Suzy', 'Al', 'Mark']
>>> sorted(names)
['Al', 'Harry', 'Mark', 'Suzy']

但是,Python使用每個字符串中第一個字母的Unicode代碼點來確定升序排序。意思是sorted()不會將名稱Al和al視為相同。此示例使用ord()返回每個字符串中第一個字母的Unicode代碼點:

>>> names_with_case = ['harry', 'Suzy', 'al', 'Mark']
>>> sorted(names_with_case)
['Mark', 'Suzy', 'al', 'harry']
>>> # 每個word中第一個字母的unicode代碼點列表推導式
>>> [(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()將使用第二個字符來確定順序,第三個字符等,依此類推,一直到字符串的結尾:

>>> very_similar_strs = ['hhhhhd', 'hhhhha', 'hhhhhc','hhhhhb']
>>> sorted(very_similar_strs)
['hhhhha', 'hhhhhb', 'hhhhhc', 'hhhhhd']

除最后一個字符外,very_similar_strs的每個值都相同。 sorted()比較字符串,因為前五個字符相同,輸出將基于第六個字符。

包含相同值的字符串將最終排序為最短到最長,因為較短的字符串沒有要與較長字符串進行比較的元素:

>>> different_lengths = ['hhhh', 'hh', 'hhhhh','h']
>>> sorted(different_lengths)
['h', 'hh', 'hhhh', 'hhhhh']

最短的字符串h排序第一,最長的字符串hhhhh排序最后。

用reverse參數(shù)使用sorted()

如sorted()的help()文檔所示,有一個名為reverse的可選關鍵字參數(shù),它將根據(jù)分配給它的布爾值更改排序行為。如果將reverse指定為True,則排序?qū)唇敌蚺帕校?/p>

>>> names = ['Harry', 'Suzy', 'Al', 'Mark']
>>> sorted(names)
['Al', 'Harry', 'Mark', 'Suzy']
>>> sorted(names, reverse=True)
['Suzy', 'Mark', 'Harry', 'Al']

排序邏輯保持不變,這意味著名稱仍按其第一個字母排序。但是,如果reverse關鍵字設置為True,則輸出反轉(zhuǎn)。

如果指定了False,則排序?qū)⒈3稚???梢允褂们懊娴娜魏问纠齺硎褂肨rue或False來查看reverse的行為:

>>> 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參數(shù)排序

sorted()最強大的功能之一是一個叫做key的關鍵字參數(shù)。此參數(shù)需要將函數(shù)傳遞給它,并且該函數(shù)將用于要排序的列表中的每個值,以確定生成的順序。

我們假設排序一個特定列表的要求是列表中字符串的長度,最短到最長。返回字符串長度len()的函數(shù)將與key參數(shù)一起使用:

>>> word = 'paper'
>>> len(word)
5
>>> words = ['banana', 'pie', 'Washington', 'book']
>>> sorted(words, key=len)
['pie', 'book', 'banana', 'Washington']

生成的順序是一個字符串順序最短到最長的列表。列表中每個元素的長度由len確定,然后以升序返回。

回到前面的例子,當大小寫不同時按第一個字母排序。key可以通過將整個字符串轉(zhuǎn)換為小寫來解決該問題:

>>> 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']

輸出值尚未轉(zhuǎn)換為小寫,因為key不會處理原始列表中的數(shù)據(jù)。在排序期間,傳遞給key的函數(shù)將在每個元素上調(diào)用以確定排序順序,但原始值仍將體現(xiàn)在輸出中。 使用帶有key參數(shù)的函數(shù)時,有兩個主要限制。

首先,傳遞給key的函數(shù)中參數(shù)的數(shù)量必須為1。

下面的示例顯示了帶有兩個參數(shù)的加法函數(shù)的定義。當該函數(shù)用于數(shù)字列表中的鍵時,它會失敗,因為它缺少第二個參數(shù)。每次在排序期間調(diào)用add()時,它一次只從列表中接收一個元素:

>>> 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 "<stdin>", line 1, in <module>
TypeError: add() missing 1 required positional argument: 'y'

第二個限制是與key一起使用的函數(shù)必須能夠處理iterable中的所有值。 例如,有一個數(shù)字列表,表示為要在sorted中使用的字符串,而key將嘗試將它們轉(zhuǎn)換為使用int。如果iterable中的值不能轉(zhuǎn)換為整數(shù),則該函數(shù)將失?。?/p>

>>> values_to_cast = ['1', '2', '3', 'four']
>>> sorted(values_to_cast, key=int)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'four'

作為字符串的每個數(shù)值都可以轉(zhuǎn)換為int,但是four不能。這會導致引發(fā)ValueError并解釋four無法轉(zhuǎn)換為int,因為它無效。

key功能非常強大,因為幾乎任何內(nèi)置或用戶定義的函數(shù)都可用于操作輸出順序。

如果排序要求是按每個字符串中的最后一個字母排序可迭代(如果字母相同,然后使用下一個字母),則可以定義函數(shù),然后在排序中使用。下面的示例定義了一個函數(shù),該函數(shù)反轉(zhuǎn)傳遞給它的字符串,然后該函數(shù)用作鍵的參數(shù):

>>> def reverse_word(word):
...     return word[::-1]
...
>>> words = ['banana', 'pie', 'Washington', 'book']
>>> sorted(words, key=reverse_word)
['banana', 'pie', 'book', 'Washington']

word[::-1]切片語法用于反轉(zhuǎn)字符串。每個元素都會應用reverse_word(),排序順序?qū)⒒诤笙騿卧~中的字符。

當然,也可以使用key參數(shù)中定義的lambda函數(shù),而不是編寫獨立函數(shù)。 lambda匿名函數(shù):1)必須內(nèi)聯(lián)定義;2)沒有名字;3)不能包含statement;4)像函數(shù)一樣執(zhí)行。

在下面的示例中,key被定義為沒有名稱的lambda,lambda采用的參數(shù)是x,然后x [:: -1]是將對參數(shù)執(zhí)行的操作:

>>> words = ['banana', 'pie', 'Washington', 'book']
>>> sorted(words, key=lambda x: x[::-1])
['banana', 'pie', 'book', 'Washington']

在每個元素上調(diào)用x [::-1]并反轉(zhuǎn)該單詞。然后將反轉(zhuǎn)的輸出用于排序,但仍返回原始單詞。 如果需求發(fā)生變化,要求順序也應該反轉(zhuǎn),那么reverse關鍵字可以與key參數(shù)一起使用:

>>> words = ['banana', 'pie', 'Washington', 'book']
>>> sorted(words, key=lambda x: x[::-1], reverse=True)
['Washington', 'book', 'pie', 'banana']

當需要基于屬性對類對象進行排序時,lambda函數(shù)也很有用。如果有一組學生并需要按最終成績(從最高到最低)對其進行排序,則可以使用lambda從該課程中獲取成績屬性:

>>> 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在每個元素上調(diào)用getattr()并返回grade的值。 reverse設置為True以使升序輸出轉(zhuǎn)為降序,以便首先排序最高等級。

當在sorted()上同時使用key和reverse關鍵字參數(shù)時,如何進行排序的可能性是無窮無盡的。當對一個小函數(shù)使用基本lambda時,代碼可以保持干凈和簡短,或者可以編寫一個全新的函數(shù)導入,并在key參數(shù)中使用它。

使用.sort()排序值

名稱相似的.sort()與sorted()內(nèi)置函數(shù)有著很大的不同。雖然它們或多或少都可以完成相同的事情,但list.sort()的help()文檔突出顯示了.sort()和sorted()之間最重要的兩個區(qū)別:

>>> # 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是列表類的一種方法,只能與列表一起使用。它不是傳遞給它的迭代的內(nèi)置函數(shù)。其次,sort返回None并修改值。我們來看看代碼中這兩種差異的影響:

>>> values_to_sort = [5, 2, 6, 1]
>>> # 嘗試調(diào)用像使用sorted()調(diào)用sort()
>>> sort(values_to_sort)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'sort' is not defined

>>> # 嘗試在一個元組上使用 .sort()
>>> tuple_val = (5, 1, 3, 5)
>>> tuple_val.sort()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'sort'

>>> # 排序列表并且賦值給新的變量
>>> sorted_values = values_to_sort.sort()
>>> print(sorted_values)
None
>>> # 打印原始變量
>>> print(values_to_sort)
[1, 2, 5, 6]

與此代碼示例中的sorted()相比,sort()操作的方式有一些非常顯著的差異:

\1. sort()不產(chǎn)生有序輸出,因此對新變量的賦值僅傳遞None類型。

\2. values_to_sort列表已就地更改,并且不以任何方式維持原始順序。

這些差異使得.sort()和sorted()絕對不能在代碼中互換,如果以錯誤的方式使用它們,它們會產(chǎn)生意想不到的結果。

.sort()具有相同的key 和reverse可選關鍵字參數(shù),這些參數(shù)產(chǎn)生與sorted()相同的強大功能。在這里,可以按第三個單詞的第二個字母對短語列表進行排序,然后反向返回列表:

>>> 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']

何時使用sorted和.sort?

我們已經(jīng)看到了sorted()和.sort()之間的區(qū)別,但我們什么時候使用?該使用哪個?

假設有一場5k比賽即將舉行:第一屆年度Python 5k。需要獲取和分類來自比賽的數(shù)據(jù),參賽者的號碼和完成比賽所需的秒數(shù):

>>> from collections import namedtuple
>>> Runner = namedtuple('Runner', 'bibnumber duration')

當參賽者越過終點線時,每個參賽者將被添加到名為參賽者的列表中。在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))

每次參賽者越過終點線時,他們的號碼號和他們的總持續(xù)時間(以秒為單位)都會添加到跑步者。

現(xiàn)在,負責處理結果數(shù)據(jù)的盡職程序員看到了這個列表,知道前5名最快的參與者是獲得獎品的獲勝者,剩下的參賽者將按最快的時間進行排序。

賽事中沒有提到通過不同屬性進行多類型的排序要求,也沒有提到將列表在某處存儲,只需按持續(xù)時間排序并獲取持續(xù)時間最短的五個參與者:

>>> runners.sort(key=lambda x: getattr(x, 'duration'))
>>> top_five_runners = runners[:5]

程序員選擇在key參數(shù)中使用lambda來獲取每個參賽者的duration屬性,并使用.sort()對運行程序進行排序。在對參賽者進行排序后,前5個元素存儲在top_five_runners中。

比賽總監(jiān)過來告訴程序員,由于目前發(fā)布的Python是3.7,他們決定每隔37位越過終點線的人將獲得一個免費的健身包。這時候,程序員開始出汗,因為參賽者名單已被不可逆轉(zhuǎn)地改變。沒有辦法按照他們完成的順序恢復原始的參賽者名單,并找到這些人。

如果你正在處理重要數(shù)據(jù),甚至可能需要恢復原始數(shù)據(jù),那么.sort()不是最佳選擇。相反,如果數(shù)據(jù)是副本,是不重要的工作數(shù)據(jù),或者沒有人會在意失不失去它,那么.sort()可以是一個很好的選擇。

因此,可以用sorted(),使用相同的lambda對runners進行排序:

>>> runners_by_duration = sorted(runners, key=lambda x: getattr(x, 'duration'))
>>> top_five_runners = runners_by_duration[:5]

在這個帶有sorted()的場景中,原始的參賽者列表仍然完好無損并且沒有被覆蓋,并且每三十七人越過終點線的即興要求可以通過與原始值互動來完成:

>>> every_thirtyseventh_runners = runners[::37]

關于Python中sorted與sort用法就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI