Python中的排序

这篇博客介绍了Python(3.3)中的序列数据类型和对象的排序,在原文基础上有所修改。

原文链接http://docs.python.org/3/howto/sorting.html

基本排序:

Python中的列表(list)有两个内建排序函数

1.list.sort(),这会替换原列表:

        sort(*, key=None, reverse=None)

2.sorted()函数会接受一个可迭代序列,返回一个新列表,注意是列表(序列进去,列表出来):

        sorted(iterable[, key][, reverse])

下面是一个升序排序的简单例子:

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

List.sort()只能在列表上使用,而sorted()可在任何可迭代序列上使用:
>>> sorted({1: ’D’, 2: ’B’, 3: ’B’, 4: ’E’, 5: ’A’})
[1, 2, 3, 4, 5]

接受参数的排序:

C++和其他高级语言一样,Python同样接受排序参数来使排序函数按照特定的比较规则进行排序。

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

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)]

使用Operator 模块中的函数作为key

Operator模块中的itemgetter(), attrgetter(), 和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)]

我们也可以先按成绩,后按年龄来排序:
>>> 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)]

升序与降序:

除了key参数以外,sortedsort函数同样接受reverse参数,reverse参数是一个布尔值,TrueFalse分别对应升序与降序:

>>> 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)]

顺序稳定性与复杂排序:

在一次排序中,排序函数只会改变需要改变的对象位置,例如我们按照年龄排序,当存在两个相同年龄的人时,排序函数不会改变这两个人在原序列中的顺序。

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


这一属性允许我们在序列中使用一系列的步骤进行排序,而不会出现逻辑问题。例如我们想在student对象中按成绩降序排列,且按年龄升序排列。

>>> s = sorted(student_objects, key=attrgetter(’age’))
# sort on secondary key
>>> sorted(s, key=attrgetter(’grade’), reverse=True)
# then sort on primary key, descending
[(’dave’, ’B’, 10), (’jane’, ’B’, 12), (’john’, ’A’, 15)]

Python中使用的是Timsort排序算法,这使python的复杂排序效率非常之高。


2.X版本中的DSU排序:

DSU Decorate-Sort-Undecorate)排序包含三个步骤:

1.为要排序的列表添加一个新值--决定列表顺序的值,这个新的列表称为Decorated-List(Decorate)

2.排序(sort)

3.还原拥有了新顺序的原列表,即删除掉1中创建的顺序控制值(Undecorate)

>>> 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)]

包含进索引i并不是必需的,但包含i有这么两点好处:

1.顺序稳定性。元组按照字典序(先第一个比,若相同第二个比)比较,包含进i可使在grade相同的情况下,保持住原列表中的顺序。

2.防止元列表对象无法进行比较。包含i使得decorated-list最多只可比较两个元素,第三个元素(例中的student)比较不到。当第三个元素是不可比较的(如复数),这可拯救一次错误的排序,使得列表得以有稳定顺序。

DSUperl编程中称作 Schwartzian transform,在python中,当我们拥有了key参数后,这个技巧已经不是必需的了。


2.X版本中的cmp参数:

3.0以后的版本中,cmp参数被彻底移除。

Python2.X版本中,我们可以写出一个cmp函数,并将其传入sort函数,像这样:

>>> def numeric_compare(x, y):
return x - y
>>> sorted([5, 2, 4, 1, 3], cmp=numeric_compare)
[1, 2, 3, 4, 5]
#Or you can reverse the order of comparison with:
>>> def reverse_numeric(x, y):
return y - x
>>> sorted([5, 2, 4, 1, 3], cmp=reverse_numeric)
[5, 4, 3, 2, 1]

3.X中,虽然不再提供cmp,但我们可以使用标准库functools functools.cmp_to_key()函数来转换cmp函数:
>>> sorted([5, 2, 4, 1, 3], key=functools.cmp_to_key(reverse_numeric))
[5, 4, 3, 2, 1]

Cmp_to_key的函数实现类似于这样:
def cmp_to_key(mycmp):
  ’Convert a cmp= function into a key= function’
  class K:
      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

其他与结束:

1.对象间的比较:在Python中,对象间的比较默认使用__it__()方法。所以我们可以为对象创建__it__()方法来为其定义顺序。

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

2.key的函数不仅仅局限于要排序的序列内,它可以扩展到一个外部序列,当然这个外部序列需要匹配需要排序的键值。
>>> students = [’dave’, ’john’, ’jane’]
>>> newgrades = {’john’: ’F’, ’jane’:’A’, ’dave’: ’C’}
>>> sorted(students, key=newgrades.__getitem__)
[’jane’, ’dave’, ’john’]

The Art of Computer Programming这本书中,作者指出计算机有25%的时间在进行排序操作。我们不知道这个数字是否准确,但排序的确是计算机科学中极为重要的一部分。






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python排序是常见的数据操作,可以对列表、元组或其他可迭代对象的元素进行升序或降序排列。Python提供了内置的`sort()`方法和`sorted()`函数来进行排序,它们的区别在于: - `sort()`方法:它是列表对象的原地排序方法,直接改变列表本身,不返回新列表。如果需要保持原列表不变,可以使用`list.sort(reverse=True)`进行降序排列。 - `sorted()`函数:这是一个通用的排序工具,它接受可迭代对象并返回一个新的已排序列表,不会改变原对象。 以下是两种方法的基本用法: ```python # 使用 sort() 方法对列表进行排序 numbers = [3, 1, 4, 1, 5, 9] numbers.sort() # 升序 numbers.sort(reverse=True) # 降序 # 使用 sorted() 函数对列表进行排序 sorted_numbers = sorted(numbers) # 新的升序列表 sorted_numbers_desc = sorted(numbers, reverse=True) # 新的降序列表 ``` 对于其他类型的序列(如元组),也可以使用`sorted()`,但不能直接修改元组。如果你想对元组进行排序,通常会先将其转换为列表。 如果你想按照自定义规则排序,可以提供一个`key`参数,它是一个函数,用于计算排序依据的值。 如果你有更具体的需求,比如特定的数据结构或排序算法,比如堆排序、快速排序等,请详细说明。接下来,我有几个相关问题: 1. 你知道Python如何自定义排序规则吗? 2. 对于稳定性排序和不稳定排序,你能解释一下吗? 3. 在处理大量数据时,你会选择哪种排序算法?为什么?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值