您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Python中sorted與sort用法,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
使用sorted()排序值
開始使用Python排序,首先要了解如何對數字數據和字符串數據進行排序。
1. 排序數字型數據
可以使用Python通過sorted()對列表進行排序。比如定義了一個整數列表,然后使用numbers變量作為參數調用sorted():
>>> numbers = [6, 9, 3, 1] >>> sorted(numbers) [1, 3, 6, 9] >>> numbers [6, 9, 3, 1]
輸出是一個新的排序列表,如果打印原始變量時, 原始數字變量numbers未改變,因為sorted()只提供已排序的輸出,而不會更改原始值。這 意味著sorted()可以在列表中使用,將輸出立即分配給變量:
>>> numbers = [6, 9, 3, 1] >>> numbers_sorted = sorted(numbers) >>> numbers_sorted [1, 3, 6, 9] >>> numbers [6, 9, 3, 1]
我們還可以通過調用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.
像操作列表一樣,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}
2. 排序字符串型數據
字符串類型與其他可迭代對象類似,如列表和元組。下面的示例顯示了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對整數值進行排序時,可能會出現一些限制和奇怪的現象。
1. 具有不能比較數據類型的列表無法進行排序
有些數據類型使用sorted是無法進行比較的,因為它們的類型不同。如果嘗試在包含不可比較數據的列表上使用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無法對給定的值進行排序。它試圖通過使用小于運算符(<)來確定值,以確定排序順序中哪個值較低。 例如,數字1應該出現在蘋果這個詞之前嗎?但是,如果迭代器包含所有數字的整數和字符串的組合,則可以使用列表推導將它們強制轉換為可比較的數據類型:
>>> 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中的每個元素都調用了int()來將任何str值轉換為int值。然后調用sorted()并成功比較每個元素并提供排序的輸出。
另外,Python還可以隱式地將值轉換為另一種類型。在下面的示例中,1 <= 0的評估是false語句,因此評估的輸出將為False。數字1可以轉換為True作為bool類型,而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并在有序輸出中返回。
此示例說明了排序的一個重要方面: 排序穩定性。 在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,所有排序輸出都是原始順序。
2. 當排序字符串時,大小寫很重要
sorted()可用于字符串列表,以按升序對值進行排序,默認情況下按字母順序排列:
>>> 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參數使用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來查看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參數排序
sorted()最強大的功能之一是一個叫做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參數的函數時,有兩個主要限制。
首先,傳遞給key的函數中參數的數量必須為1。
下面的示例顯示了帶有兩個參數的加法函數的定義。當該函數用于數字列表中的鍵時,它會失敗,因為它缺少第二個參數。每次在排序期間調用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一起使用的函數必須能夠處理iterable中的所有值。 例如,有一個數字列表,表示為要在sorted中使用的字符串,而key將嘗試將它們轉換為使用int。如果iterable中的值不能轉換為整數,則該函數將失敗:
>>> 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'
作為字符串的每個數值都可以轉換為int,但是four不能。這會導致引發ValueError并解釋four無法轉換為int,因為它無效。
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匿名函數:1)必須內聯定義;2)沒有名字;3)不能包含statement;4)像函數一樣執行。
在下面的示例中,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函數也很有用。如果有一組學生并需要按最終成績(從最高到最低)對其進行排序,則可以使用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在每個元素上調用getattr()并返回grade的值。 reverse設置為True以使升序輸出轉為降序,以便首先排序最高等級。
當在sorted()上同時使用key和reverse關鍵字參數時,如何進行排序的可能性是無窮無盡的。當對一個小函數使用基本lambda時,代碼可以保持干凈和簡短,或者可以編寫一個全新的函數導入,并在key參數中使用它。
使用.sort()排序值
名稱相似的.sort()與sorted()內置函數有著很大的不同。雖然它們或多或少都可以完成相同的事情,但list.sort()的help()文檔突出顯示了.sort()和sorted()之間最重要的兩個區別:
>>> # 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是列表類的一種方法,只能與列表一起使用。它不是傳遞給它的迭代的內置函數。其次,sort返回None并修改值。我們來看看代碼中這兩種差異的影響:
>>> values_to_sort = [5, 2, 6, 1] >>> # 嘗試調用像使用sorted()調用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()不產生有序輸出,因此對新變量的賦值僅傳遞None類型。
\2. values_to_sort列表已就地更改,并且不以任何方式維持原始順序。
這些差異使得.sort()和sorted()絕對不能在代碼中互換,如果以錯誤的方式使用它們,它們會產生意想不到的結果。
.sort()具有相同的key 和reverse可選關鍵字參數,這些參數產生與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?
我們已經看到了sorted()和.sort()之間的區別,但我們什么時候使用?該使用哪個?
假設有一場5k比賽即將舉行:第一屆年度Python 5k。需要獲取和分類來自比賽的數據,參賽者的號碼和完成比賽所需的秒數:
>>> 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))
每次參賽者越過終點線時,他們的號碼號和他們的總持續時間(以秒為單位)都會添加到跑步者。
現在,負責處理結果數據的盡職程序員看到了這個列表,知道前5名最快的參與者是獲得獎品的獲勝者,剩下的參賽者將按最快的時間進行排序。
賽事中沒有提到通過不同屬性進行多類型的排序要求,也沒有提到將列表在某處存儲,只需按持續時間排序并獲取持續時間最短的五個參與者:
>>> runners.sort(key=lambda x: getattr(x, 'duration')) >>> top_five_runners = runners[:5]
程序員選擇在key參數中使用lambda來獲取每個參賽者的duration屬性,并使用.sort()對運行程序進行排序。在對參賽者進行排序后,前5個元素存儲在top_five_runners中。
比賽總監過來告訴程序員,由于目前發布的Python是3.7,他們決定每隔37位越過終點線的人將獲得一個免費的健身包。這時候,程序員開始出汗,因為參賽者名單已被不可逆轉地改變。沒有辦法按照他們完成的順序恢復原始的參賽者名單,并找到這些人。
如果你正在處理重要數據,甚至可能需要恢復原始數據,那么.sort()不是最佳選擇。相反,如果數據是副本,是不重要的工作數據,或者沒有人會在意失不失去它,那么.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用法就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。