MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Python列表排序的性能对比

2021-08-164.1k 阅读

Python列表排序的性能对比

在Python编程中,对列表进行排序是一项常见的操作。Python提供了多种方式来对列表进行排序,每种方式在性能上可能会有所不同。深入了解这些排序方法的性能差异,对于优化程序、提高运行效率至关重要。本文将详细对比Python中不同列表排序方式的性能,并通过代码示例展示其用法和性能差异。

Python内置的排序方法

sorted函数

sorted() 是Python的内置函数,它会返回一个新的已排序列表,而原列表保持不变。以下是其基本用法:

my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
sorted_list = sorted(my_list)
print(sorted_list)  

在上述代码中,sorted(my_list)my_list 进行排序并返回一个新的列表,原 my_list 依旧是 [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]

sorted() 函数具有很高的灵活性,它可以接受多个参数。其中,key 参数可以指定一个函数,用于提取比较的键。例如,当我们有一个包含字典的列表,想要根据字典中的某个键进行排序时,就可以使用 key 参数:

students = [
    {'name': 'Alice', 'age': 20},
    {'name': 'Bob', 'age': 18},
    {'name': 'Charlie', 'age': 22}
]
sorted_students = sorted(students, key=lambda student: student['age'])
print(sorted_students)  

上述代码通过 key=lambda student: student['age'] 指定按照学生字典中的 age 键进行排序。

reverse 参数则用于指定是否以降序排序,默认为 False(升序)。当设置为 True 时,会以降序排列:

my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
descending_sorted_list = sorted(my_list, reverse=True)
print(descending_sorted_list)  

list.sort方法

list.sort() 是列表对象的方法,它会直接在原列表上进行排序,不会返回新的列表。其基本用法如下:

my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
my_list.sort()
print(my_list)  

sorted() 函数类似,list.sort() 也可以接受 keyreverse 参数:

students = [
    {'name': 'Alice', 'age': 20},
    {'name': 'Bob', 'age': 18},
    {'name': 'Charlie', 'age': 22}
]
students.sort(key=lambda student: student['age'])
print(students)  

性能对比:sorted函数与list.sort方法

从功能上看,sorted() 函数和 list.sort() 方法都能实现列表排序。然而,在性能方面,由于 sorted() 函数返回新的列表,需要额外的内存空间来存储新列表,这在处理大规模数据时可能会对性能产生一定影响。而 list.sort() 方法直接在原列表上操作,节省了创建新列表的开销。

为了更直观地对比它们的性能,我们可以使用 timeit 模块。timeit 模块可以测量小段代码的执行时间。以下是对比 sorted() 函数和 list.sort() 方法性能的代码示例:

import timeit

my_list = list(range(10000))

def test_sorted():
    return sorted(my_list)

def test_list_sort():
    temp_list = my_list.copy()
    temp_list.sort()
    return temp_list

sorted_time = timeit.timeit(test_sorted, number = 1000)
list_sort_time = timeit.timeit(test_list_sort, number = 1000)

print(f'sorted函数执行1000次的时间: {sorted_time} 秒')
print(f'list.sort方法执行1000次的时间: {list_sort_time} 秒')

在上述代码中,我们首先创建了一个包含10000个元素的列表 my_list。然后定义了两个测试函数 test_sorted()test_list_sort(),分别使用 sorted() 函数和 list.sort() 方法对列表进行排序。为了使对比公平,test_list_sort() 中先对原列表进行了复制,因为 list.sort() 会改变原列表。最后使用 timeit.timeit() 函数分别测量两个函数执行1000次的时间。

通常情况下,运行上述代码后会发现 list.sort() 方法的执行时间会比 sorted() 函数略短,这体现了其在原地排序的性能优势。但在实际应用中,如果需要保留原列表,那么 sorted() 函数则是更好的选择,即使它在性能上稍有劣势。

使用第三方库进行排序

NumPy库

NumPy是Python中常用的数学计算库,它提供了高效的数组操作。虽然NumPy主要用于处理数组,但通过将列表转换为NumPy数组,也可以利用其排序功能。NumPy的排序算法经过优化,在处理大规模数据时可能具有更好的性能。

以下是使用NumPy进行排序的示例代码:

import numpy as np

my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
np_array = np.array(my_list)
sorted_np_array = np.sort(np_array)
print(sorted_np_array)  

在上述代码中,我们首先将Python列表 my_list 转换为NumPy数组 np_array,然后使用 np.sort() 方法对其进行排序。np.sort() 方法返回一个新的已排序列表,原数组保持不变。

与Python内置的排序方法类似,np.sort() 也支持按特定轴进行排序。例如,当处理二维数组时,可以指定按行或按列排序:

import numpy as np

two_d_array = np.array([[3, 1, 4], [1, 5, 9], [2, 6, 5]])
sorted_by_row = np.sort(two_d_array, axis = 1)
sorted_by_column = np.sort(two_d_array, axis = 0)

print('按行排序:')
print(sorted_by_row)
print('按列排序:')
print(sorted_by_column)

在上述代码中,axis = 1 表示按行排序,axis = 0 表示按列排序。

Pandas库

Pandas是用于数据处理和分析的强大库。在处理表格数据(如DataFrame)时,Pandas提供了排序功能。以下是使用Pandas对DataFrame进行排序的示例:

import pandas as pd

data = {
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [20, 18, 22]
}
df = pd.DataFrame(data)
sorted_df = df.sort_values(by='Age')
print(sorted_df)  

在上述代码中,我们创建了一个DataFrame df,然后使用 sort_values() 方法按 Age 列进行排序。sort_values() 方法会返回一个新的已排序DataFrame,原DataFrame保持不变。

与Python内置排序方法类似,sort_values() 也支持多列排序以及指定排序顺序(升序或降序):

import pandas as pd

data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'David'],
    'Age': [20, 18, 22, 20],
    'Score': [85, 90, 78, 88]
}
df = pd.DataFrame(data)
sorted_df = df.sort_values(by=['Age', 'Score'], ascending=[True, False])
print(sorted_df)  

在上述代码中,by=['Age', 'Score'] 表示按 AgeScore 两列进行排序,ascending=[True, False] 表示 Age 列升序排列,Score 列降序排列。

性能对比:内置方法与第三方库

为了对比Python内置排序方法与第三方库(如NumPy和Pandas)的性能,我们同样可以使用 timeit 模块。以下是对比Python内置 sorted() 函数与NumPy的 np.sort() 方法性能的代码示例:

import timeit
import numpy as np

my_list = list(range(100000))

def test_sorted():
    return sorted(my_list)

def test_np_sort():
    np_array = np.array(my_list)
    return np.sort(np_array)

sorted_time = timeit.timeit(test_sorted, number = 100)
np_sort_time = timeit.timeit(test_np_sort, number = 100)

print(f'sorted函数执行100次的时间: {sorted_time} 秒')
print(f'np.sort方法执行100次的时间: {np_sort_time} 秒')

在上述代码中,我们创建了一个包含100000个元素的列表 my_list。然后定义了两个测试函数 test_sorted()test_np_sort(),分别使用 sorted() 函数和 np.sort() 方法对列表进行排序。最后使用 timeit.timeit() 函数分别测量两个函数执行100次的时间。

通常情况下,当数据量较大时,NumPy的 np.sort() 方法会比Python内置的 sorted() 函数更快。这是因为NumPy是用C语言实现的,其底层算法经过高度优化,在处理大规模数值数据时具有显著的性能优势。

接下来对比Python内置 list.sort() 方法与Pandas的 sort_values() 方法在处理表格数据时的性能。以下是示例代码:

import timeit
import pandas as pd

data = {
    'Name': [f'Name_{i}' for i in range(10000)],
    'Age': [i % 100 for i in range(10000)],
    'Score': [i % 200 for i in range(10000)]
}

def test_list_sort():
    temp_list = list(zip(data['Age'], data['Score'], data['Name']))
    temp_list.sort()
    sorted_age, sorted_score, sorted_name = zip(*temp_list)
    return {'Name': list(sorted_name), 'Age': list(sorted_age), 'Score': list(sorted_score)}

def test_pd_sort():
    df = pd.DataFrame(data)
    sorted_df = df.sort_values(by=['Age', 'Score'])
    return sorted_df

list_sort_time = timeit.timeit(test_list_sort, number = 100)
pd_sort_time = timeit.timeit(test_pd_sort, number = 100)

print(f'list.sort方法执行100次的时间: {list_sort_time} 秒')
print(f'pandas.sort_values方法执行100次的时间: {pd_sort_time} 秒')

在上述代码中,我们创建了一个包含10000条记录的模拟表格数据。test_list_sort() 函数将数据转换为元组列表,使用 list.sort() 方法进行排序,然后再将排序后的数据转换回字典形式。test_pd_sort() 函数则直接使用Pandas的 sort_values() 方法对DataFrame进行排序。最后使用 timeit.timeit() 函数分别测量两个函数执行100次的时间。

在处理这种表格数据时,Pandas的 sort_values() 方法通常会在性能上优于使用Python内置 list.sort() 方法手动实现的排序,因为Pandas针对表格数据的操作进行了优化,提供了更高效的数据结构和算法。

不同排序算法的性能影响

Python的内置排序方法(sorted() 函数和 list.sort() 方法)通常使用Timsort算法。Timsort是一种自适应的、稳定的排序算法,它结合了归并排序和插入排序的优点。在面对不同的数据分布时,Timsort能够自动选择更合适的排序策略,从而在大多数情况下都能表现出较好的性能。

对于NumPy的 np.sort() 方法,在不同版本和平台下可能会使用不同的排序算法。例如,在某些情况下会使用快速排序算法的优化版本。快速排序是一种高效的排序算法,平均时间复杂度为O(n log n),但在最坏情况下(如数据已经有序)时间复杂度会退化到O(n²)。不过,NumPy对快速排序进行了优化,以减少最坏情况出现的概率。

Pandas的 sort_values() 方法内部同样使用了经过优化的排序算法,其具体实现与DataFrame的数据结构和存储方式紧密相关。Pandas会根据数据类型和数据量等因素选择合适的排序策略,以确保在处理各种表格数据时都能有较好的性能表现。

总结不同排序方式的适用场景

  1. Python内置的 sorted() 函数:适用于需要保留原列表,并且对性能要求不是极其苛刻的场景。例如,在一些小型脚本或对代码简洁性要求较高的地方,使用 sorted() 函数可以很方便地获得一个已排序列表,而无需担心原列表被修改。
  2. Python内置的 list.sort() 方法:当不需要保留原列表,并且希望尽可能提高排序性能时,list.sort() 方法是更好的选择。它直接在原列表上进行操作,避免了创建新列表的开销,在处理大规模列表时能节省内存和时间。
  3. NumPy的 np.sort() 方法:适用于处理大规模数值数据。由于NumPy的底层实现使用C语言,并且其排序算法经过优化,在处理纯数值列表转换为NumPy数组后的排序操作时,通常会比Python内置方法更快。在科学计算和数据分析中,如果涉及对大量数值数据的排序,NumPy是一个很好的选择。
  4. Pandas的 sort_values() 方法:专门用于处理表格数据,即DataFrame。当需要对包含多列数据的表格按某一列或多列进行排序时,Pandas提供了简洁且高效的接口。其性能在处理表格数据时通常优于手动使用Python内置方法实现的排序,因为Pandas针对表格数据的操作进行了优化。

通过深入了解Python中不同列表排序方式的性能特点和适用场景,开发者可以根据具体的需求选择最合适的排序方法,从而提高程序的运行效率和性能。无论是在小型脚本还是大规模数据处理项目中,选择正确的排序方式都能为代码的优化带来显著的效果。

在实际开发中,还需要根据数据的规模、数据类型以及具体的业务需求等多方面因素综合考虑。如果对性能要求极高,可能还需要进一步对代码进行性能分析和优化,例如通过并行计算等方式来提高排序效率。同时,随着Python版本的更新和第三方库的发展,排序算法和性能也可能会有所变化,开发者需要持续关注相关的技术动态,以确保代码始终保持最佳性能。

以上就是关于Python列表排序性能对比的详细内容,希望通过本文的介绍和示例代码,能帮助你在实际编程中更明智地选择排序方式,提升程序性能。