开放的编程资料库

当前位置:我爱分享网 > Python教程 > 正文

Python排序列表

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有两个基本的列表排序函数:sortsortedsort对列表进行就地排序,而sorted从iterable中的项目返回一个新的排序列表。这两个函数具有相同的选项:keyreversekey采用一个函数,该函数将用于正在排序的列表中的每个值以确定结果顺序。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命名元组具有三个属性:idnamepopulation。该示例按名称对命名元组进行排序。

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教程。

未经允许不得转载:我爱分享网 » Python排序列表

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏