Python 排序

最简单的排序方法是使用 sort(list) 函数,该函数会获取一个列表并返回按排序顺序包含这些元素的新列表。原始列表不会发生更改。

  a = [5, 1, 4, 3]
  print(sorted(a))  ## [1, 3, 4, 5]
  print(a)  ## [5, 1, 4, 3]

最常见的做法是将列表传递给 Sort() 函数,但事实上,它可以将任何类型的可迭代集合作为输入。较旧的 list.sort() 方法是一种备选方法,详见下文。与“sort()”相比,“sort()”函数似乎更易于使用,因此我们建议您使用“sort()”。

可以通过可选参数自定义 Sort() 函数。sort() 可选参数 back=True,例如challenge(list, return=True):用于向后排序。

  strs = ['aa', 'BB', 'zz', 'CC']
  print(sorted(strs))  ## ['BB', 'CC', 'aa', 'zz'] (case sensitive)
  print(sorted(strs, reverse=True))   ## ['zz', 'aa', 'CC', 'BB']

使用 key= 的自定义排序

对于更复杂的自定义排序,sort() 可使用可选的“key=”指定一个“key”函数,它会在比较之前对每个元素进行转换。键函数接受 1 个值并返回 1 个值,以及返回的“proxy”值用于排序中的比较。

例如,如果使用字符串列表,指定 key=len(内置的 len() 函数)就会按长度从最短到最长对字符串排序。排序针对每个字符串调用 len() 以获取代理长度值的列表,然后使用这些代理值进行排序。

  strs = ['ccc', 'aaaa', 'd', 'bb']
  print(sorted(strs, key=len))  ## ['d', 'bb', 'ccc', 'aaaa']

调用已按 key=len 排序

再举一例,指定“str.lower”因为关键函数是强制排序对大小写相同的处理:

  ## "key" argument specifying str.lower function to use for sorting
  print(sorted(strs, key=str.lower))  ## ['aa', 'BB', 'CC', 'zz']

您还可以将自己的 MyFn 作为键函数传入,如下所示:

  ## Say we have a list of strings we want to sort by the last letter of the string.
  strs = ['xc', 'zb', 'yd' ,'wa']

  ## Write a little function that takes a string, and returns its last letter.
  ## This will be the key function (takes in 1 value, returns 1 value).
  def MyFn(s):
    return s[-1]

  ## Now pass key=MyFn to sorted() to sort by the last letter:
  print(sorted(strs, key=MyFn))  ## ['wa', 'zb', 'xc', 'yd']

对于更复杂的排序(例如先按姓氏排序,然后按名字排序), 您可以使用 itemgetter 或 attrgetter 函数,例如:

  from operator import itemgetter

  # (first name, last name, score) tuples
  grade = [('Freddy', 'Frank', 3), ('Anil', 'Frank', 100), ('Anil', 'Wang', 24)]
  sorted(grade, key=itemgetter(1,0))
  # [('Anil', 'Frank', 100), ('Freddy', 'Frank', 3), ('Anil', 'Wang', 24)]

  sorted(grade, key=itemgetter(0,-1))
  #[('Anil', 'Wang', 24), ('Anil', 'Frank', 100), ('Freddy', 'Frank', 3)]

排序() 方法

作为 sort()的替代方法,对列表的 sort()方法会按升序对列表进行排序,例如list.sort()。order() 方法会更改底层列表并返回 None,因此请按如下方式使用它:

  alist.sort()            ## correct
  alist = blist.sort()    ## Incorrect. sort() returns None

以上是对 order() 的很常见误解 - 它 *不会返回* 已排序的列表。必须对列表调用 sort() 方法;它对任何可枚举的集合都不起作用(但上面的 sort() 函数适用于任何对象)。sort() 方法早于 order() 函数,因此您可能会在旧版代码中看到它。排序() 方法不需要创建新列表,因此,如果要排序的元素已存在于列表中,则其速度会快一些。

元组

元组是固定大小的元素分组,例如 (x, y) 坐标。元组与列表类似,只不过它们是不可变的,也不会改变大小(元组并非绝对不可变,因为所包含的某个元素可能是可变的)。元组是一种“结构体”角色)来轻松传递一些有逻辑的固定大小值包。需要返回多个值的函数只能返回一个值的元组。例如,如果我希望有一个三维坐标列表,那么自然的 Python 表示法将是元组列表,其中每个元组的大小都是 3,其中包含一个 (x, y, z) 组。

要创建元组,只需列出括号中的值(以英文逗号分隔)。“空”元组只是一对空圆括号。访问元组中的元素就像访问列表一样,len()、[ ]、for、in 等都是一样的。

  tuple = (1, 2, 'hi')
  print(len(tuple))  ## 3
  print(tuple[2])    ## hi
  tuple[2] = 'bye'  ## NO, tuples cannot be changed
  tuple = (1, 2, 'bye')  ## this works

要创建 size-1 元组,孤立元素必须后跟英文逗号。

  tuple = ('hi',)   ## size-1 tuple

这在语法中十分有趣,但要将元组与用括号括住表达式的普通情况区分开来,则必须使用逗号。在某些情况下,您可以省略括号,而 Python 则会从逗号中发现您想要创建元组的逗号。

如果将元组分配给大小相同的变量名称元组,则会分配所有相应的值。如果元组的大小不同,则会抛出错误。此功能也适用于清单。

  (x, y, z) = (42, 13, "hike")
  print(z)  ## hike
  (err_string, err_code) = Foo()  ## Foo() returns a length-2 tuple

列表理解(可选)

列表理解是一项更高级的功能,在某些情况下很有用,但练习不需要,您最初需要学习的内容也不需要(即您可以跳过本部分)。列表理解是一种紧凑的方式来编写可展开为整个列表的表达式。假设我们有一个列表编号 [1, 2, 3, 4],以下是计算这些方格 [1, 4, 9, 16] 列表的列表理解:

  nums = [1, 2, 3, 4]

  squares = [ n * n for n in nums ]   ## [1, 4, 9, 16]

语法为 [ expr for var in list ]for var in list 看起来像常规的 for 循环,但没有冒号 (:)。系统会针对每个元素计算一次左侧 expr 的值,从而为新列表提供值。下面是一个字符串示例,其中每个字符串都改为大写,并带有“!!!”附加内容:

  strs = ['hello', 'and', 'goodbye']

  shouting = [ s.upper() + '!!!' for s in strs ]
  ## ['HELLO!!!', 'AND!!!', 'GOODBYE!!!']

您可以在 for 循环的右侧添加一个 if 测试,以缩小结果范围。系统会为每个元素评估 if 测试,只对测试为 true 的元素进行评估。

  ## Select values <= 2
  nums = [2, 8, 1, 6]
  small = [ n for n in nums if n <= 2 ]  ## [2, 1]

  ## Select fruits containing 'a', change to upper case
  fruits = ['apple', 'cherry', 'banana', 'lemon']
  afruits = [ s.upper() for s in fruits if 'a' in s ]
  ## ['APPLE', 'BANANA']

练习:list1.py

要练习本部分中的资料,请稍后尝试 list1.py 中使用排序和元组的问题(在基本练习中)。