python 排序

简介:

Python list内置sort()方法用来排序,也可以用python内置的全局sorted()方法来对可迭代的序列排序生成新的序列。

 

1)排序基础

简单的升序排序是非常容易的。只需要调用sorted()方法。它返回一个新的list,新的list的元素基于小于运算符(__lt__)来排序。

>>> sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]

 

你也可以使用list.sort()方法来排序,此时list本身将被修改。通常此方法不如sorted()方便,但是如果你不需要保留原来的list,此方法将更有效。

>>> a = [5, 2, 3, 1, 4]
>>> a.sort()
>>> a
[1, 2, 3, 4, 5]

 

另一个不同就是list.sort()方法仅被定义在list中,相反地sorted()方法对所有的可迭代序列都有效。

 

>>> sorted({1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'})
[1, 2, 3, 4, 5]

 

 

2)key参数/函数

从python2.4开始,list.sort()和sorted()函数增加了key参数来指定一个函数,此函数将在每个元素比


较前被调用。 例如通过key指定的函数来忽略字符串的大小写:


>>> sorted("This is a test string from Andrew".split(), key=str.lower)


['a''Andrew''from''is''string''test''This']

 

key参数的值为一个函数,此函数只有一个参数且返回一个值用来进行比较。这个技术是快速的因为key


指定的函数将准确地对每个元素调用。

 

更广泛的使用情况是用复杂对象的某些值来对复杂对象的序列排序,例如:

>>> student_tuples = [
        ('john''A', 15),
        ('jane''B', 12),
        ('dave''B', 10),
]
>>> sorted(student_tuples, key=lambda student: student[2])   # sort by age


[('dave''B', 10), ('jane''B', 12), ('john''A', 15)]

 

同样的技术对拥有命名属性的复杂对象也适用,例如:

>>> class Student:
        def __init__(self, name, grade, age):
                self.name = name
                self.grade = grade
                self.age = age
        def __repr__(self):
                return repr((self.name, self.grade, self.age))
>>> student_objects = [
        Student('john''A', 15),
        Student('jane''B', 12),
        Student('dave''B', 10),
]
>>> sorted(student_objects, key=lambda student: student.age)   # sort by age
[('dave''B', 10), ('jane''B', 12), ('john''A', 15)]

 

3)Operator 模块函数

上面的key参数的使用非常广泛,因此python提供了一些方便的函数来使得访问方法更加容易和快速。operator模块有itemgetter,attrgetter,从2.6开始还增加了methodcaller方法。使用这些方法,上面的操作将变得更加简洁和快速:

>>> from operator import itemgetter, attrgetter


>>> sorted(student_tuples, key=itemgetter(2))


[('dave''B', 10), ('jane''B', 12), ('john''A', 15)]


>>> sorted(student_objects, key=attrgetter('age'))


[('dave''B', 10), ('jane''B', 12), ('john''A', 15)]

 

operator模块还允许多级的排序,例如,先以grade,然后再以age来排序:


>>> sorted(student_tuples, key=itemgetter(1,2))


[('john''A', 15), ('dave''B', 10), ('jane''B', 12)]


>>> sorted(student_objects, key=attrgetter('grade''age'))


[('john''A', 15), ('dave''B', 10), ('jane''B', 12)]

 

4)升序和降序

list.sort()和sorted()都接受一个参数reverse(True or False)来表示升序或降序排序。例如对上面的student降序排序如下:

>>> sorted(student_tuples, key=itemgetter(2), reverse=True)


[('john''A', 15), ('jane''B', 12), ('dave''B', 10)]


>>> sorted(student_objects, key=attrgetter('age'), reverse=True)


[('john''A', 15), ('jane''B', 12), ('dave''B', 10)]

 

5)排序的稳定性和复杂排序

从python2.2开始,排序被保证为稳定的。意思是说多个元素如果有相同的key,则排序前后他们的先后顺序不变。

>>> data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
>>> sorted(data, key=itemgetter(0))
[('blue', 1), ('blue', 2), ('red', 1), ('red', 2)]

注意在排序后'blue'的顺序被保持了,即'blue', 1在'blue', 2的前面。

 

更复杂地你可以构建多个步骤来进行更复杂的排序,例如对student数据先以grade降序排列,然后再以age升序排列。

>>> s = sorted(student_objects, key=attrgetter('age'))     # sort on secondary key


>>> sorted(s, key=attrgetter('grade'), reverse=True)       # now sort on primary key, descending
[('dave''B', 10), ('jane''B', 12), ('john''A', 15)]

 

6)最老土的排序方法-DSU

我们称其为DSU(Decorate-Sort-Undecorate),原因为排序的过程需要下列三步:

第一:对原始的list进行装饰,使得新list的值可以用来控制排序;

第二:对装饰后的list排序;

第三:将装饰删除,将排序后的装饰list重新构建为原来类型的list;

 

例如,使用DSU方法来对student数据根据grade排序:

>>> decorated = [(student.grade, i, student) for i, student in enumerate(student_objects)]
>>> decorated.sort()
>>> [student for grade, i, student in decorated]               # undecorate
[('john''A', 15), ('jane''B', 12), ('dave''B', 10)]

上面的比较能够工作,原因是tuples是可以用来比较,tuples间的比较首先比较tuples的第一个元素,如果第一个相同再比较第二个元素,以此类推。

 

并不是所有的情况下都需要在以上的tuples中包含索引,但是包含索引可以有以下好处:

第一:排序是稳定的,如果两个元素有相同的key,则他们的原始先后顺序保持不变;

第二:原始的元素不必用来做比较,因为tuples的第一和第二元素用来比较已经是足够了。

 

此方法被RandalL.在perl中广泛推广后,他的另一个名字为也被称为Schwartzian transform。

 

对大的list或list的元素计算起来太过复杂的情况下,在python2.4前,DSU很可能是最快的排序方法。但是在2.4之后,上面解释的key函数提供了类似的功能。

 

7)其他语言普遍使用的排序方法-cmp函数

在python2.4前,sorted()和list.sort()函数没有提供key参数,但是提供了cmp参数来让用户指定比较函数。此方法在其他语言中也普遍存在。

 

在python3.0中,cmp参数被彻底的移除了,从而简化和统一语言,减少了高级比较和__cmp__方法的冲突。

 

在python2.x中cmp参数指定的函数用来进行元素间的比较。此函数需要2个参数,然后返回负数表示小于,0表示等于,正数表示大于。例如:

>>> def numeric_compare(x, y):
        return x - y
>>> sorted([5, 2, 4, 1, 3], cmp=numeric_compare)
[1, 2, 3, 4, 5]

 

或者你可以反序排序:

>>> def reverse_numeric(x, y):
        return y - x
>>> sorted([5, 2, 4, 1, 3], cmp=reverse_numeric)
[5, 4, 3, 2, 1]

 

当我们将现有的2.x的代码移植到3.x时,需要将cmp函数转化为key函数,以下的wrapper很有帮助:

def cmp_to_key(mycmp):
    'Convert a cmp= function into a key= function'
    class K(object):
        def __init__(self, obj, *args):
            self.obj = obj
        def __lt__(self, other):
            return mycmp(self.obj, other.obj) < 0
        def __gt__(self, other):
            return mycmp(self.obj, other.obj) > 0
        def __eq__(self, other):
            return mycmp(self.obj, other.obj) == 0
        def __le__(self, other):
            return mycmp(self.obj, other.obj) <= 0
        def __ge__(self, other):
            return mycmp(self.obj, other.obj) >= 0
        def __ne__(self, other):
            return mycmp(self.obj, other.obj) != 0
    return K

 

当需要将cmp转化为key时,只需要:

>>> sorted([5, 2, 4, 1, 3], key=cmp_to_key(reverse_numeric))
[5, 4, 3, 2, 1]

从python2.7,cmp_to_key()函数被增加到了functools模块中。 


8)其他注意事项

* 对需要进行区域相关的排序时,可以使用locale.strxfrm()作为key函数,或者使用local.strcoll()作为cmp函数。

 

* reverse参数任然保持了排序的稳定性,有趣的时,同样的效果可以使用reversed()函数两次来实现:

>>> data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
>>> assert sorted(data, reverse=True) == list(reversed(sorted(reversed(data))))

 

其实排序在内部是调用元素的__cmp__来进行的,所以我们可以为元素类型增加__cmp__方法使得元素可比较,例如:

>>> Student.__lt__ = lambda self, other: self.age < other.age
>>> sorted(student_objects)
[('dave''B', 10), ('jane''B', 12), ('john''A', 15)]

 

* key函数不仅可以访问需要排序元素的内部数据,还可以访问外部的资源,例如,如果学生的成绩是存储在dictionary中的,则可以使用此dictionary来对学生名字的list排序,如下:

>>> students = ['dave''john''jane']
>>> newgrades = {'john''F''jane':'A''dave''C'}
>>> sorted(students, key=newgrades.__getitem__)
['jane''dave''john']

 

*当你需要在处理数据的同时进行排序的话,sort(),sorted()或bisect.insort()不是最好的方法。在这种情况下,可以使用heap,red-black tree或treap。


1.字符串列表排序

列表的排序是python内置功能,自身含有sort方法 。如果元素是字符串,会分解成字符比较,而字符的大小是根据字符对应ascii码的大小。

Python代码  收藏代码

>>> str_list = ['spring', 'summer', 'autumn', 'winter']  

>>> str_list.sort()  

>>> print str_list  

['autumn', 'spring', 'summer', 'winter']  

 

Python代码  收藏代码

>>> str_list = ['aB', 'Ab', 'AB', 'ab']  

>>> str_list.sort()  

>>> print str_list  

['AB', 'Ab', 'aB', 'ab']  

 

Python代码  收藏代码

>>> str_list = ['a123', 'B123', 'c123']  

>>> str_list.sort()  

>>> print str_list  

['B123', 'a123', 'c123']  

 如果忽略大小字母,让上面结果显示为:['a123', 'B123', 'c123']。怎么做了?

 

很容易想到DSU用法,decorate-sort-undecorate封装-排序-解封,既简单又快速:

Python代码  收藏代码

>>> str_list = ['c123', 'a123', 'B123']  


>>> temp_list = [(x.lower(), x) for x in str_list]  #decorate

  

>>> temp_list.sort()  #sort  


>>> str_list = [x[1] for x in temp_list]  #undecorate  


>>> print str_list  


['a123', 'B123', 'c123']  

这是一种重要的编程思想,你现在所处的情景,你想要的结果,你要做的就是搭一座桥梁,让两者之间可以联通!这是的桥梁就是temp_list。

 

如果你确定列表中的元素都是字符串,而且你使用的是Python2.4以上版本,那么使用sorted方法来得更简单:

Python代码  收藏代码

>>> str_list = ['c123', 'a123', 'B123']  

>>> sorted(str_list, key=str.lower)  


>>> str_list = sorted(str_list, key=str.lower)  

['a123', 'B123', 'c123']  

 这里我提示一点sorted方法并没有直接作用于目标列表,而是返回一个排序后的列表。如果你知道排序的是unicode对象列表,可以使用key=unicode.lower,或者key = lambda s: s.lower()

 

这里给你补充点知识:

        python有三种字符串类型:str、unicode、basestring。basestring是抽象类,不能实例化,str和unicode是basestring的子类。普通字符串str怎么转换为Unicode字符串?'Hello'+u' '+'World'   这样就行了,连接中有一个是unicode字符串,结果都为unicode字符串。如果你想知道得更详细,我会写另一篇文章。

        lambda 是匿名函数,python中非常有用的一个函数,掌握它对你受益匪浅。

 

这里你会不禁赞叹python的强大,简单而且优美。程序就是一件艺术品,python无疑是一把优质的雕琢刀,而你的地位恰好是雕塑家。成功与否,不是取决于雕琢刀的好坏,而是你雕刻的方法,这正是我们应该学习的!

 

也许上面两种方法你都没有想到,你想到的是:难道不能重新构造比较方法cmp()吗?

Python代码  收藏代码

>>> def mycmp(a, b):  

    return cmp(a.lower(), b.lower())  

  

>>> str_list = ['c123', 'a123', 'B123']  

>>> str_list.sort(mycmp)  

>>> print str_list  

['a123', 'B123', 'c123']  

 不知你发现没有,每两个元素进行比较都会执行两次lower()方法,如果列表中元素为n,那要执行多少次lower()?虽然不推荐这样做,但也给我们提供了一种思路,如果不是字符串列表,而是结构很复杂的数据列表,我们就可以采用这样方法!

2.数字列表排序

Python代码  收藏代码

>>> num_list = [12, 43, 11, 23, 9]  

>>> num_list.sort()  

>>> print num_list  

[9, 11, 12, 23, 43]  

 小数也同样适用

Python代码  收藏代码

>>> num_list = [12, 43.4, 11.5, 23.0, 9.1]  

>>> num_list.sort()  

>>> print num_list  

[9.1, 11.5, 12, 23.0, 43.4]  

 我用的是Python2.7,如果你使用是其他版本,可能会出现不同的结果,如:9.1变成9.100000000001 。这涉及到python中小数是怎么存储的,这里就不多说了!

 

3.字典数据排序

学Java的人都知道Map,而字典就是Python中的“Map”,键值对映射。字典中元素的存储是无序的,怎么对字典数据进行排序?

Python代码  收藏代码

>>> mydict = {"A01":"first", "A14":"second", "Aa1":"third"}  

>>> print mydict  

{'A14': 'second', 'A01': 'first', 'Aa1': 'third'}  

>>> items = mydict.items()  

>>> print items  

[('A14', 'second'), ('A01', 'first'), ('Aa1', 'third')]  

>>> items.sort()  

>>> print items  

[('A01', 'first'), ('A14', 'second'), ('Aa1', 'third')]  

>>> new_list = [value for key, value in items]  

>>> print new_list  

['first', 'second', 'third']  

 前3行说明字典中元素存储是无序的,你构造的字典和实际存储的字典 里元素的顺序并不一样!字典的items()方法能够把字典转换为元组的列表,再对元组列表进行排序,得到自己想要的结果。

 

另一种思路:得到字典key列表,排序后,依次取出value,构造成列表就是你的结果。

Python代码  收藏代码

>>> mydict = {"A01":"first", "A14":"second", "Aa1":"third"}  

>>> keys = mydict.keys()  

>>> keys.sort()  

>>> new_list = [mydict[key] for key in keys] 

 

>>> print new_list  

['first', 'second', 'third']  

 通过映射的方法更有效的执行最后一步

Python代码  收藏代码

>>> mydict = {"A01":"first", "A14":"second", "Aa1":"third"}  

>>> keys = mydict.keys()  

>>> keys.sort()  

>>> new_list = map( mydict.get,keys )  

>>> print new_list  

['first', 'second', 'third']  

 利用lamdba函数,选择根据key或value排序

Python代码  收藏代码

>>> sorted(mydict.items(), key=lambda d:d[0])  

[('A01', 'first'), ('A14', 'second'), ('Aa1', 'third')]  

>>> mydict = {"A01":"first", "A14":"second", "Aa1":"third"}  

>>> sorted(mydict.items(), key=lambda d:d[0])  

[('A01', 'first'), ('A14', 'second'), ('Aa1', 'third')]  

>>> sorted(mydict.items(), key=lambda d:d[1])  

[('A01', 'first'), ('A14', 'second'), ('Aa1', 'third')]  

>>> print mydict  

{'A14': 'second', 'A01': 'first', 'Aa1': 'third'}  

 

4.对象排序

 

Python代码  收藏代码

>>> class Sortobj:  

    a = 0  

    b = ''  

    def __init__(self, a, b):  

        self.a = a  

        self.b = b  

    def printab(self):  

        print self.a, self.b  

  

          

>>> obja = Sortobj(343, 'keen')  

>>> objb = Sortobj(56, 'blue')  

>>> objc = Sortobj(2, 'aba')  

>>> objd = Sortobj(89, 'iiii')  

>>> obj_list = [obja, objb, objc, objd]  

>>> for obj in obj_list:  

    obj.printab()  

  

      

343 keen  

56 blue  

2 aba  

89 iiii  

>>> obj_list.sort(lambda x,y: cmp(x.a, y.a)) #按对象的a属性进行排序  

>>> for obj in obj_list:  

    obj.printab()  

  

      

2 aba  

56 blue  

89 iiii  

343 keen  

>>> obj_list.sort(lambda x,y: cmp(x.b, y.b)) #按对象的b属性进行排序  

>>> for obj in obj_list:  

    obj.printab()  

  

      

2 aba  

56 blue  

89 iiii  

343 keen  

 

5.字典列表排序

元素全是字典的列表,如何排序?其实把上面的方法综合起来就能实现:

Python代码  收藏代码

input = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10},{'name': 'Wang', 'age':10},{'name': 'Ab', 'age':10}]  

print input  

input.sort(lambda x,y : cmp(x['name'], y['name']))   

print input  

如果想降序排列,

Python代码  收藏代码

input.sort(lambda x,y : -cmp(x['name'], y['name']))  










本文转自 chengxuyonghu 51CTO博客,原文链接:http://blog.51cto.com/6226001001/1552973,如需转载请自行联系原作者
目录
相关文章
|
3月前
|
Python
在 Python 中,对列表进行排序有两种常用的方法
在 Python 中,对列表进行排序有两种常用的方法
|
4月前
|
Python
Python小技巧:一种字符串的排序方式
该文介绍了如何对包含数字的字符串列表进行特定排序。首先,示例了一个初始问题,使用Python内置的`sorted()`函数未能达到预期(按数字部分升序排序)。然后,文章提出通过自定义排序键`sort_key`来解决,利用正则表达式提取字符串尾部数字并进行排序。进一步,文章扩展到处理如&#39;nxxx_name_nxxx&#39;格式的字符串,通过给前缀和后缀数字赋予不同权重进行复合排序,展示了如何实现先按前缀、再按后缀排序的功能。提供的代码示例成功地完成了任务。
|
29天前
|
Python
【Python】对字典进行排序
该文档介绍了如何在Python中对字典进行排序的方法。
15 2
|
2月前
|
Python
Python小技巧:一种字符串的排序方式
Python小技巧:一种字符串的排序方式
17 0
|
2月前
|
分布式计算 并行计算 算法
探索排序的宇宙奥秘:Python中归并排序的并行处理与分布式应用!
【7月更文挑战第11天】归并排序是一种分治算法,适用于并行和分布式处理。在Python中,利用`concurrent.futures`可实现并行归并排序,但因GIL限制,可能需借助`multiprocessing`或GPU库。分布式归并排序则通过分布式框架如Apache Spark处理大规模数据,每个节点独立排序后进行网络合并。并行与分布式技术提升了处理大数据的速度和效率。**
31 9
|
2月前
|
搜索推荐 Python
快速排序的 Python 实践:从原理到优化,打造你的排序利器!
【7月更文挑战第12天】Python的快速排序**以分治策略实现高效排序,平均时间复杂度$O(nlogn)$,优于$O(n^2)$的冒泡排序。基本实现通过选取基准元素分割数组,然后递归排序两部分。优化版使用随机基准避免最坏情况。对比显示优化后排序更稳定,适应不同数据集,提升程序性能。
41 4
|
2月前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
【7月更文挑战第12天】归并排序是高效稳定的排序算法,采用分治策略。Python 实现包括递归地分割数组及合并已排序部分。示例代码展示了如何将 `[12, 11, 13, 5, 6]` 分割并归并成有序数组 `[5, 6, 11, 12, 13]`。虽然 $O(n log n)$ 时间复杂度优秀,但需额外空间,适合大规模数据排序。对于小规模数据,可考虑其他算法。**
62 4
|
26天前
|
算法 索引 Python
【Leetcode刷题Python】34. 在排序数组中查找元素的第一个和最后一个位置(二分查找)
解决LeetCode "在排序数组中查找元素的第一个和最后一个位置" 问题的方法。第一种方法是使用两次二分查找,首先找到目标值的最左边界,然后找到最右边界。第二种方法是利用Python的list.index()方法,先正序找到起始位置,再逆序找到结束位置,并给出了两种方法的Python实现代码。
35 0
|
26天前
|
Python
【Python】对key或values是datetime类型或时间字符串的字典dict排序
本文提供了针对字典中key为时间字符串或datetime类型时进行排序的解决方案,包括将时间字符串转换为datetime对象排序和直接对datetime类型的key排序的方法。
30 0
|
2月前
|
搜索推荐 算法 大数据
Python排序大法揭秘!归并排序:如何优雅地合并两个世界?
【7月更文挑战第11天】归并排序是Python中一种高效优雅的排序算法,基于分而治之的思想,将数组拆分成小部分,分别排序后再合并。Python实现归并排序的关键在于递归地分割和有序合并数组。其稳定性和O(n log n)的时间复杂度使其在大数据处理中表现出色。通过学习归并排序,我们可以深化对编程思维的理解并提升解决问题的能力。
36 1
下一篇
云函数