Python 列表排序
最后修改于 2024 年 9 月 16 日
在本文中,我们将介绍如何在 Python 语言中对列表元素进行排序。
排序
在计算机科学中,排序是指将元素按有序序列排列。多年来,人们开发了多种算法来对数据进行排序,包括归并排序、快速排序、选择排序或冒泡排序。(排序的另一种含义是分类,即将具有相似属性的元素分组。)
排序的相反操作,即将元素序列重新排列成随机或无意义的顺序,称为打乱。
数据可以按字母顺序或数字顺序排序。排序键指定了执行排序所依据的标准。可以按多个键对对象进行排序。例如,在对用户进行排序时,可以将用户的姓名作为主要排序键,职业作为次要排序键。
排序顺序
标准顺序称为升序:a 到 z,0 到 9。反向顺序称为降序:z 到 a,9 到 0。对于日期和时间,升序表示较早的值排在较晚的值之前,例如 1/1/2020 会排在 1/1/2021 之前。
稳定排序
稳定排序是指在排序过程中保持相等元素的初始相对顺序。有些排序算法天然稳定,有些则不稳定。例如,归并排序和冒泡排序是稳定的排序算法。另一方面,堆排序和快速排序是不稳定排序算法的示例。
考虑以下值:3715593。稳定排序的结果如下:1335579。值 3 和 5 的顺序得以保留。不稳定排序可能产生以下结果:1335579。
Python 使用 timsort 算法。这是一种混合稳定排序算法,源自归并排序和插入排序。它由 Tim Peters 于 2002 年为 Python 编程语言实现。
Python 排序函数
Python 有两个基本的列表排序函数:sort 和 sorted。sort 会就地对列表进行排序,而 sorted 则从可迭代对象中的项返回一个新的排序后的列表。两个函数具有相同的选项: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 示例
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 函数,该函数根据给定的字符串创建一个 datetime 对象。实际上,sort 函数对 datetime 对象进行排序。
如果您不熟悉 lambda 关键字,请在 Python lambda 教程中了解更多关于匿名函数的信息。
$. /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 作为键函数。
import locale
words = ['zem', 'čučoriedka', 'drevo', 'hrozno', 'hora', 'džem', 'element',
'štebot', 'cesta', 'černice', 'ďateľ', 'rum', 'železo', 'prameň', 'sob',
'chobot', 'chmel', 'cmar', 'džús', 'dzekať']
locale.setlocale(locale.LC_COLLATE, ('sk_SK', 'UTF8'))
words.sort(key=locale.strxfrm)
for word in words:
print(word)
此示例对斯洛伐克语单词进行排序。
$ ./locale_sort.py cesta cesta cmar černice čučoriedka ďateľ drevo dzekať džem džús element hora hrozno chmel chobot 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)
通过将 str.lower 函数传递给 key 属性,我们可以执行不区分大小写的排序。
$ ./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)
匿名函数返回命名元组的 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)
itemgetter 和 attrgetter 函数
Python 提供了 itemgetter 和 attrgetter 便利函数,以使访问函数更轻松、更快速。它们位于 operator 模块中。
#!/usr/bin/python
from typing import NamedTuple
from operator import itemgetter, attrgetter
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]
sorted_cities = sorted(cities, key=attrgetter('name'))
for city in sorted_cities:
print(city)
print('---------------------')
sorted_cities = sorted(cities, key=itemgetter(2))
for city in sorted_cities:
print(city)
我们使用 sorted 和这些辅助函数对城市列表进行排序。
sorted_cities = sorted(cities, key=attrgetter('name'))
我们传递用于排序城市的属性名称。
sorted_cities = sorted(cities, key=itemgetter(2))
对于 itemgetter,我们传递属性的索引。
$ ./named_tuple_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) --------------------- City(id=1, name='Bratislava', population=432000) City(id=6, name='Edinburgh', population=464000) City(id=3, name='Prague', population=1280000) City(id=4, name='Warsaw', population=1748000) City(id=2, name='Budapest', population=1759000) City(id=7, name='Berlin', population=3671000) City(id=5, name='Los Angeles', population=3971000)
Python 按多个排序标准排序列表
以下示例按两个排序标准对学生列表进行排序。
#!/usr/bin/python
from typing import NamedTuple
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]
students.sort(key=lambda s: (s.grade, s.age))
for student in students:
print(student)
我们按成绩然后按年龄对学生进行排序。排序是升序的。
students.sort(key=lambda s: (s.grade, s.age))
要进行排序,我们将 lambda 函数传递一个排序属性的元组。
$ ./multiple_sort.py Student(id=7, name='Sofia', grade='A', age=18) Student(id=1, name='Patrick', grade='A', age=21) Student(id=4, name='Monika', grade='A', age=22) Student(id=2, name='Lucia', grade='B', age=19) Student(id=9, name='Arnold', grade='B', age=23) 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)
我们可能希望按多个标准对数据进行排序,并具有不同的排序类型。
第一个解决方案是将键包装在一个类中,该类定义了排序类型。
#!/usr/bin/python
from typing import NamedTuple
class negate:
def __init__(self, obj):
self.obj = obj
def __eq__(self, other):
return other.obj == self.obj
def __lt__(self, other):
return other.obj < self.obj
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]
students.sort(key=lambda s: (s.grade, negate(s.age)))
for student in students:
print(student)
此示例按成绩升序排序学生,然后按年龄降序排序。
students.sort(key=lambda s: (s.grade, negate(s.age)))
第二个键被 negate 包装。
$ ./multi_sort2.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)
另一种解决方案是两次排序列表。
#!/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_sort3.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)
扑克牌排序
以下示例对一副扑克牌进行排序。
import random
from itertools import groupby
def create_deck():
signs = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A']
symbols = ['♠', '♥', '♦', '♣'] # spades, hearts, diamonds, clubs
deck = [f'{si}{sy}' for si in signs for sy in symbols]
return deck
def by_poker_order(card):
poker_order = "2 3 4 5 6 7 8 9 10 J Q K A"
return poker_order.index(card[:-1])
def by_suit(card):
return card[-1]
deck = create_deck()
random.shuffle(deck)
# Sort by poker order and then by suit
deck.sort(key=by_poker_order)
deck.sort(key=by_suit)
for k, g in groupby(deck, key=lambda c: c[-1]):
print(k, list(g))
代码示例创建一副牌。它按花色对牌进行分组并排序。
def create_deck():
signs = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A']
symbols = ['♠', '♥', '♦', '♣'] # spades, hearts, diamonds, clubs
deck = [f'{si}{sy}' for si in signs for sy in symbols]
return deck
create_deck 方法创建一副扑克牌。有十三种点数和四种花色。
def by_poker_order(card):
poker_order = "2 3 4 5 6 7 8 9 10 J Q K A"
return poker_order.index(card[:-1])
该方法返回牌的点数索引。这用于对牌进行排序。
def by_suit(card):
return card[-1]
by_suit 方法用于按花色对牌进行排序。它返回牌组中的牌的花色字符;它是最后一个字符。
random.shuffle(deck)
使用 random.shuffle 随机重新组织牌。
deck.sort(key=by_poker_order) deck.sort(key=by_suit)
我们先按扑克顺序然后按花色对牌组进行排序。
for k, g in groupby(deck, key=lambda c: c[-1]):
print(k, list(g))
我们使用 groupby 函数按花色形成四个组。
$ ./main.py ♠ ['2♠', '3♠', '4♠', '5♠', '6♠', '7♠', '8♠', '9♠', '10♠', 'J♠', 'Q♠', 'K♠', 'A♠'] ♣ ['2♣', '3♣', '4♣', '5♣', '6♣', '7♣', '8♣', '9♣', '10♣', 'J♣', 'Q♣', 'K♣', 'A♣'] ♥ ['2♥', '3♥', '4♥', '5♥', '6♥', '7♥', '8♥', '9♥', '10♥', 'J♥', 'Q♥', 'K♥', 'A♥'] ♦ ['2♦', '3♦', '4♦', '5♦', '6♦', '7♦', '8♦', '9♦', '10♦', 'J♦', 'Q♦', 'K♦', 'A♦']
Python 排序自定义复杂对象列表 - 硬币包
我们有一个自定义对象,一个命名元组,它有一种特定的排序方式。
sort 和 sorted 在排序时仅使用 __lt__ 魔术方法。所以我们只需要实现这个方法。但是,PEP8 建议出于安全和代码完整性的考虑,实现所有六个操作(__eq__ 、__ne__ 、__lt__ 、__le__ 、__gt__、__ge__)。来自 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
__lt__ 方法用于 Python 排序函数比较两个对象。我们必须计算两个袋子中所有硬币的价值并进行比较。
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 教程。