Python列表排序教程展示了如何使用Python语言对列表元素进行排序。
排序
在计算机科学中,排序是按有序顺序排列元素。多年来,开发了多种算法来对数据进行排序,包括归并排序、快速排序、选择排序或冒泡排序。(排序的另一个意思是归类,是将具有相似属性的元素分组。)
与排序相反,以随机或无意义的顺序重新排列元素序列,称为洗牌。
数据可以按字母顺序或数字顺序排序。排序键指定用于执行排序的条件。可以通过多个键对对象进行排序。例如,在对用户进行排序时,可以将用户的姓名作为主排序键,将职业作为次排序键。
排序顺序
标准顺序称为升序:a到z,0到9。相反的顺序称为降序:z到a,9到0。对于日期和时间,升序意味着较早的值在较晚的值之前,例如1/1/2020将在1/1/2021之前进行排序。
稳定排序
稳定排序是保留相等元素的初始顺序的排序。有些排序算法天生稳定,有些则不稳定。例如,归并排序和冒泡排序是稳定的排序算法。另一方面,堆排序和快速排序是不稳定排序算法的例子。
考虑以下值:3715593
。稳定排序产生以下结果:1335579
。值3和5的顺序保持不变。不稳定的排序可能会产生以下结果:1335579
。
Python使用timsort算法。它是一种混合稳定排序算法,源自归并排序和插入排序。它由TimPetersin于2002年实现,用于Python编程语言。
Python排序函数
Python有两个基本的列表排序函数:sort
和sorted
。sort
对列表进行就地排序,而sorted
从iterable中的项目返回一个新的排序列表。这两个函数具有相同的选项:key
和reverse
。key
采用一个函数,该函数将用于正在排序的列表中的每个值以确定结果顺序。reverse
选项可以颠倒比较顺序。
这两个函数都会产生稳定的排序。
Python就地排序列表
列表容器的sort
函数在排序时修改了原始列表。
#!/usr/bin/python words = ['forest', 'wood', 'tool', 'arc', 'sky', 'poor', 'cloud', 'rock'] vals = [2, 1, 0, 3, 4, 6, 5, 7] words.sort() print(words) vals.sort() print(vals)
在示例中,我们对字符串和整数列表进行排序。原始列表已修改。
$ ./inplace_sort.py ['arc', 'cloud', 'forest', 'poor', 'rock', 'sky', 'tool', 'wood'] [0, 1, 2, 3, 4, 5, 6, 7]
Python排序示例
sorted
函数不修改原始列表;相反,它会创建一个新的修改列表。
#!/usr/bin/python words = ['forest', 'wood', 'brisk', 'tree', 'sky', 'cloud', 'rock', 'falcon'] sorted_words = sorted(words) print('Original:', words) print('Sorted:', sorted_words)
该示例从原始列表中创建一个新的排序单词列表,该列表是完整的。
$ ./sorted_fun.py Original: ['forest', 'wood', 'brisk', 'tree', 'sky', 'cloud', 'rock', 'falcon'] Sorted: ['brisk', 'cloud', 'falcon', 'forest', 'rock', 'sky', 'tree', 'wood']
Python升序/降序排序列表
升序/降序通过reverse
选项控制
。
#!/usr/bin/python words = ['forest', 'wood', 'tool', 'arc', 'sky', 'poor', 'cloud', 'rock'] words.sort() print(words) words.sort(reverse=True) print(words)
该示例按升序和降序对单词列表进行排序。
$ ./asc_desc.py ['arc', 'cloud', 'forest', 'poor', 'rock', 'sky', 'tool', 'wood'] ['wood', 'tool', 'sky', 'rock', 'poor', 'forest', 'cloud', 'arc']
Python排序日期列表
在下一个示例中,我们对日期列表进行排序。
#!/usr/bin/python from datetime import datetime values = ['8-Nov-19', '21-Jun-16', '1-Nov-18', '7-Apr-19'] values.sort(key=lambda d: datetime.strptime(d, "%d-%b-%y")) print(values)
匿名函数使用strptime
函数,它根据给定的字符串创建一个日期时间对象。实际上,sort
函数对日期时间对象进行排序。
如果您不熟悉lambda关键字,请在Pythonlambda教程中了解有关匿名函数的更多信息。
$. /sort_date.py ['21-Jun-16', '1-Nov-18', '7-Apr-19', '8-Nov-19']
Python按元素索引排序列表
Python列表可以有嵌套的迭代器。在这种情况下,我们可以选择应该排序的元素。
#!/usr/bin/python vals = [(4, 0), (0, -2), (3, 5), (1, 1), (-1, 3)] vals.sort() print(vals) vals.sort(key=lambda e: e[1]) print(vals)
该示例首先按第一个元素对嵌套元组进行排序,然后按第二个元素排序。
vals.sort(key=lambda e: e[1])
通过提供返回元组第二个元素的匿名函数,我们可以根据第二个值对元组进行排序。
$ ./sort_elem_idx.py [(-1, 3), (0, -2), (1, 1), (3, 5), (4, 0)] [(0, -2), (4, 0), (1, 1), (-1, 3), (3, 5)]
Python根据嵌套列表的总和对列表进行排序
假设我们有嵌套列表,它们都有不同的排名。最终排名是所有值的总和。
#!/usr/bin/python data = [[10, 11, 12, 13], [9, 10, 11, 12], [8, 9, 10, 11], [10, 9, 8, 7], [6, 7, 8, 9], [5, 5, 5, 1], [5, 5, 5, 5], [3, 4, 5, 6], [10, 1, 1, 2]] data.sort() print(data) data.sort(key=sum) print(data)
默认情况下,排序函数按嵌套列表的第一个值排序。为了实现我们的目标,我们将内置的sum
函数传递给key
选项.
$ ./sort_sum.py [[3, 4, 5, 6], [5, 5, 5, 1], [5, 5, 5, 5], [6, 7, 8, 9], [8, 9, 10, 11], [9, 10, 11, 12], [10, 1, 1, 2], [10, 9, 8, 7], [10, 11, 12, 13]] [[10, 1, 1, 2], [5, 5, 5, 1], [3, 4, 5, 6], [5, 5, 5, 5], [6, 7, 8, 9], [10, 9, 8, 7], [8, 9, 10, 11], [9, 10, 11, 12], [10, 11, 12, 13]]
该示例显示了默认排序和自定义排序。
本地化字符串的Python排序列表
对于区域设置感知排序,我们可以使用locale.strxfrm
作为键函数。
#!/usr/bin/python import locale words = ['zem', 'ÄuÄoriedka', 'drevo', 'Å¡tebot', 'cesta', 'Äernice', 'Äateľ', 'rum', 'železo', 'prameÅ', 'sob'] locale.setlocale(locale.LC_COLLATE, ('sk_SK', 'UTF8')) words.sort(key=locale.strxfrm) for word in words: print (word)
该示例对斯洛伐克语单词进行排序。
$ ./locale_sort.py cesta Äernice ÄuÄoriedka Äateľ drevo prameÅ rum sob Å¡tebot zem železo
Python排序字典列表
在对字典进行排序时,我们可以选择执行排序所依据的属性。
#!/usr/bin/python users = [ {'name': 'John Doe', 'date_of_birth': 1987}, {'name': 'Jane Doe', 'date_of_birth': 1996}, {'name': 'Robert Brown', 'date_of_birth': 1977}, {'name': 'Lucia Smith', 'date_of_birth': 2002}, {'name': 'Patrick Dempsey', 'date_of_birth': 1994} ] users.sort(reverse=True, key=lambda e: e['date_of_birth']) for user in users: print(user)
我们有一个用户列表。每个用户都由一个字典表示。
users.sort(reverse=True, key=lambda e: e['date_of_birth'])
在匿名函数中,我们选择date_of_birth
属性。
$ ./sort_dict.py {'name': 'Lucia Smith', 'date_of_birth': 2002} {'name': 'Jane Doe', 'date_of_birth': 1996} {'name': 'Patrick Dempsey', 'date_of_birth': 1994} {'name': 'John Doe', 'date_of_birth': 1987} {'name': 'Robert Brown', 'date_of_birth': 1977}
用户按出生日期降序排列。
Python排序成绩列表
世界各地有多种分级系统。我们的示例包含A+或C-等等级,这些等级不能按字典顺序排列。我们使用字典,其中每个等级都有其给定值。
#!/usr/bin/python data = 'A+ A A- B+ B B- C+ C C- D+ D' grades = { grade: idx for idx, grade in enumerate(data.split()) } def mc(e): return grades.get(e[1]) students = [('Anna', 'A+'), ('Jozef', 'B'), ('Rebecca', 'B-'), ('Michael', 'D+'), ('Zoltan', 'A-'), ('Jan', 'A'), ('Michelle', 'C-'), ('Sofia', 'C+')] print(grades) students.sort(key=mc) print(students) # from operator import itemgetter # students.sort(key=lambda e: itemgetter(e[1])(grades))
我们有一份学生名单。每个学生在嵌套元组中都有姓名和成绩。
data = 'A+ A A- B+ B B- C+ C C- D+ D' grades = { grade: idx for idx, grade in enumerate(data.split()) }
我们建立成绩字典。每个等级都有它的价值。成绩将按其字典值排序。
def mc(e): return grades.get(e[1])
关键函数只是返回成绩的值。
# from operator import itemgetter # students.sort(key=lambda e: itemgetter(e[1])(grades))
此解决方案使用匿名函数。
$ ./grades.py {'A+': 0, 'A': 1, 'A-': 2, 'B+': 3, 'B': 4, 'B-': 5, 'C+': 6, 'C': 7, 'C-': 8, 'D+': 9, 'D': 10} [('Anna', 'A+'), ('Jan', 'A'), ('Zoltan', 'A-'), ('Jozef', 'B'), ('Rebecca', 'B-'), ('Sofia', 'C+'), ('Michelle', 'C-'), ('Michael', 'D+')]
Python按字符串长度排序列表
有时,我们需要根据字符串的长度对字符串进行排序。
#!/usr/bin/python def w_len(e): return len(e) words = ['forest', 'wood', 'tool', 'sky', 'poor', 'cloud', 'rock', 'if'] words.sort(reverse=True, key=w_len) print(words)
在这个例子中,我们不使用匿名函数。
def w_len(e): return len(e)
w_len
函数返回每个元素的长度。
$ ./sort_by_len.py ['forest', 'cloud', 'wood', 'tool', 'poor', 'rock', 'sky', 'if']
单词按长度降序排列。
Python按大小写排序
默认情况下,首字母大写的字符串排在其他字符串之前。我们也可以不管大小写对字符串进行排序。
#!/usr/bin/python text = 'Today is a beautiful day. Andy went fishing.' words = text.replace('.', '') sorted_words = sorted(words.split(), key=str.lower) print('Case insensitive:', sorted_words) sorted_words2 = sorted(words.split()) print('Case sensitive:', sorted_words2)
通过为key属性提供str.lower
函数,我们执行不区分大小写的排序。
$ ./case_sorting.py Case insensitive: ['a', 'Andy', 'beautiful', 'day', 'fishing', 'is', 'Today', 'went'] Case sensitive: ['Andy', 'Today', 'a', 'beautiful', 'day', 'fishing', 'is', 'went']
Python按姓氏排序列表
在下面的示例中,我们按姓氏对姓名进行排序。
#!/usr/bin/python names = ['John Doe', 'Jane Doe', 'Robert Brown', 'Robert Novak', 'Lucia Smith', 'Patrick Dempsey', 'George Marshall', 'Alan Brooke', 'Harold Andras', 'Albert Doe'] names.sort() names.sort(key=lambda e: e.split()[-1]) for name in names: print(name)
我们有一份名单。每个名字都由名字和姓氏组成。此外,还有多个同姓用户。在这种情况下,我们希望他们按名字排序。
names.sort() names.sort(key=lambda e: e.split()[-1])
首先,我们按名字对名字进行排序。然后我们按姓氏对名字进行排序。为此,我们拆分每个字符串并选择最后一个字符串(它的索引为-1)。由于Python的排序算法是稳定的,因此会记住第一次排序并得到预期的输出。
$ ./sort_by_lastname.py Harold Andras Alan Brooke Robert Brown Patrick Dempsey Albert Doe Jane Doe John Doe George Marshall Robert Novak Lucia Smith
姓名按姓氏排序。Doe用户按名字正确排序。
命名元组的Python排序列表
在下一个示例中,我们对命名元组进行排序。
#!/usr/bin/python from typing import NamedTuple class City(NamedTuple): id: int name: str population: int c1 = City(1, 'Bratislava', 432000) c2 = City(2, 'Budapest', 1759000) c3 = City(3, 'Prague', 1280000) c4 = City(4, 'Warsaw', 1748000) c5 = City(5, 'Los Angeles', 3971000) c6 = City(6, 'Edinburgh', 464000) c7 = City(7, 'Berlin', 3671000) cities = [c1, c2, c3, c4, c5, c6, c7] cities.sort(key=lambda e: e.name) for city in cities: print(city)
City
命名元组具有三个属性:id
、name
和population
。该示例按名称对命名元组进行排序。
cities.sort(key=lambda e: e.name)
匿名函数返回命名元组的名称属性。
$ ./namedtuple_sort.py City(id=7, name='Berlin', population=3671000) City(id=1, name='Bratislava', population=432000) City(id=2, name='Budapest', population=1759000) City(id=6, name='Edinburgh', population=464000) City(id=5, name='Los Angeles', population=3971000) City(id=3, name='Prague', population=1280000) City(id=4, name='Warsaw', population=1748000)
Python根据多个排序条件对列表进行排序
以下示例按两个排序标准对学生列表进行排序。
#!/usr/bin/python from typing import NamedTuple from operator import attrgetter def multi_sort(data, specs): for key, reverse in reversed(specs): data.sort(key=attrgetter(key), reverse=reverse) return data class Student(NamedTuple): id: int name: str grade: str age: int s1 = Student(1, 'Patrick', 'A', 21) s2 = Student(2, 'Lucia', 'B', 19) s3 = Student(3, 'Robert', 'C', 19) s4 = Student(4, 'Monika', 'A', 22) s5 = Student(5, 'Thomas', 'D', 20) s6 = Student(6, 'Petra', 'B', 18) s6 = Student(7, 'Sofia', 'A', 18) s7 = Student(8, 'Harold', 'E', 22) s8 = Student(9, 'Arnold', 'B', 23) students = [s1, s2, s3, s4, s5, s6, s7, s8] multi_sort(students, (('grade', False), ('age', True))) for student in students: print(student)
首先,学生按成绩升序排列,然后按年龄降序排列。
def multi_sort(data, specs): for key, reverse in reversed(specs): data.sort(key=attrgetter(key), reverse=reverse) return data
multi_sort
方法应用列表中的所有排序规范。
$ ./multi_sort.py Student(id=4, name='Monika', grade='A', age=22) Student(id=1, name='Patrick', grade='A', age=21) Student(id=7, name='Sofia', grade='A', age=18) Student(id=9, name='Arnold', grade='B', age=23) Student(id=2, name='Lucia', grade='B', age=19) Student(id=3, name='Robert', grade='C', age=19) Student(id=5, name='Thomas', grade='D', age=20) Student(id=8, name='Harold', grade='E', age=22)
自定义复杂对象的Python排序列表-硬币袋
我们有一个自定义对象,一个namedtuple,它有一种特定的排序方式。
functools
模块中的total_ordering
装饰器有助于减少样板文件。total_ordering
需要__eq__
和要实现的其余方法之一。
#!/usr/bin/python from typing import NamedTuple from functools import total_ordering # a gold coin equals to two silver and six bronze coins class Coin(NamedTuple): rank: str @total_ordering class Pouch: def __init__(self): self.bag = [] def add(self, coin): self.bag.append(coin) def __eq__(self, other): val1, val2 = self.__evaluate(other) if val1 == val2: return True else: return False def __lt__(self, other): val1, val2 = self.__evaluate(other) if val1 < val2: return True else: return False def __str__(self): return f'Pouch with: {self.bag}' def __evaluate(self, other): val1 = 0 val2 = 0 for coin in self.bag: if coin.rank == 'g': val1 += 6 if coin.rank == 's': val1 += 3 if coin.rank == 'b': val1 += 1 for coin in other.bag: if coin.rank == 'g': val2 += 6 if coin.rank == 's': val2 += 3 if coin.rank == 'b': val2 += 1 return val1, val2 def create_pouches(): p1 = Pouch() p1.add(Coin('g')) p1.add(Coin('b')) p1.add(Coin('s')) p2 = Pouch() p2.add(Coin('g')) p2.add(Coin('s')) p3 = Pouch() p3.add(Coin('b')) p3.add(Coin('s')) p3.add(Coin('s')) p4 = Pouch() p4.add(Coin('b')) p4.add(Coin('s')) p5 = Pouch() p5.add(Coin('g')) p5.add(Coin('s')) p5.add(Coin('s')) p5.add(Coin('b')) p5.add(Coin('b')) p5.add(Coin('b')) p6 = Pouch() p6.add(Coin('b')) p6.add(Coin('b')) p6.add(Coin('b')) p6.add(Coin('b')) p6.add(Coin('b')) p7 = Pouch() p7.add(Coin('g')) p8 = Pouch() p8.add(Coin('g')) p8.add(Coin('g')) p8.add(Coin('s')) bag = [p1, p2, p3, p4, p5, p6, p7, p8] return bag bag = create_pouches() bag.sort() for e in bag: print(e)
在示例中,我们对硬币袋进行分类。钱币分为金币、银币和青铜币三种。一枚金币等于两枚银币和六枚铜币。(因此,一银币等于三铜币。)
class Coin(NamedTuple): rank: str
我们的自定义对象是一个命名元组,它有一个属性:rank
。
@total_ordering class Pouch: def __init__(self): self.bag = [] def add(self, coin): self.bag.append(coin) ...
Pouch
有一个内部self.bag
列表用于存储它的硬币。在类中,我们有两种比较方法:__lt__
和__eq__
。@total_ordering
装饰器提供其余部分。
def __lt__(self, other): val1, val2 = self.__evaluate(other) if val1 < val2: return True else: return False
Python排序函数使用__lt__
方法来比较两个对象。我们必须计算两个袋子中所有硬币的价值并进行比较。
def __str__(self): return f'Pouch with: {self.bag}'
__str__
给出了Pouch
对象的人类可读表示。
def __evaluate(self, other): val1 = 0 val2 = 0 for coin in self.bag: if coin.rank == 'g': val1 += 6 if coin.rank == 's': val1 += 3 if coin.rank == 'b': val1 += 1 for coin in other.bag: if coin.rank == 'g': val2 += 6 if coin.rank == 's': val2 += 3 if coin.rank == 'b': val2 += 1 return val1, val2
__evaluate
方法计算两个袋子的值。它将两个值返回给__lt__
进行比较。
def create_pouches(): p1 = Pouch() p1.add(Coin('g')) p1.add(Coin('b')) p1.add(Coin('s')) p2 = Pouch() p2.add(Coin('g')) p2.add(Coin('s')) ...
在create_pouches
函数中,我们创建了八个装有不同数量硬币的小袋。
bag.sort() for e in bag: print(e)
我们对袋子的袋子进行分类,然后打印分类袋子的元素。
$ ./coins.py Pouch with: [Coin(rank='b'), Coin(rank='s')] Pouch with: [Coin(rank='b'), Coin(rank='b'), Coin(rank='b'), Coin(rank='b'), Coin(rank='b')] Pouch with: [Coin(rank='g')] Pouch with: [Coin(rank='b'), Coin(rank='s'), Coin(rank='s')] Pouch with: [Coin(rank='g'), Coin(rank='s')] Pouch with: [Coin(rank='g'), Coin(rank='b'), Coin(rank='s')] Pouch with: [Coin(rank='g'), Coin(rank='s'), Coin(rank='s'), Coin(rank='b'), Coin(rank='b'), Coin(rank='b')] Pouch with: [Coin(rank='g'), Coin(rank='g'), Coin(rank='s')]
这是输出。两枚金币一枚银币的荷包最值钱。
在本教程中,我们介绍了Python中列表的排序操作。
列出所有Python教程。