sorted()

转载须注明出处:简书@Orca_J35 | GitHub@orca-j35

🔨sorted(iterable, *, key=None, reverse=False)

sorted 函数会对 iterable 对象执行排序操作,并返回一个内含排序结果的新列表。

各参数含义如下:

  • iterable : 一个可迭代对象
  • key : 一个单参数可调用对象(如 key=str.lower),该对象用于提取 iterable 中各个元素的比较键(comparison key),并以"比较键"的顺序作为排序依据。如果保持默认值 None,则会直接比较 iterable 中的各个元素。
  • reverse : 一个布尔值,用于控制排列顺序。默认值 False 表示以升序排列 iterable 中的元素;True 则表示以降序排列 iterable 中的元素。

一些简单的列子:

# 直接比较iterable中的各个元素,升序排列
>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]
>>> sorted('dcabegf')
['a', 'b', 'c', 'd', 'e', 'f', 'g']

# 以iterable中各元素的绝对值作为排序依据
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]

# 降序排列
>>> sorted([36, 5, -12, 9, -21], reverse=True)
[36, 9, 5, -12, -21]

# 字符串默认按ASCII排序,因此大小写会影响排序结果
>>> sorted(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']

# 排序时忽略大小写
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
['about', 'bob', 'Credit', 'Zoo']

扩展阅读"Sorting HOW TO" 作为一个排序教程提供了更多参考示例。

稳定性

稳定性排序(stable-sort)算法在对相同元素进行排序时,不会改变这些元素在排序之前的相对位置。比如当我们按照牌面值进行排序时:在稳定性排序中,红心 5 和黑桃 5 的前后顺序保持不变;而在非稳定性算法中,两者的顺序则可能会发生改变。

Stable sort.png

sorted 函数采用稳定性排序算法,可以看到花色顺序不会改变:

>>> cards = [(7,"黑桃"), (5,"红桃"), (2,"红桃"), (5,"黑桃")]
>>> sorted(cards, key=lambda item:item[0])
[(2, '红桃'), (5, '红桃'), (5, '黑桃'), (7, '黑桃')]

当数据需要连续经历多个排序步骤时(比如先按部门排序,再按工资等级排序),稳定性排序算法会非常实用,因为它不会改变上一步已排列好的顺序。

>>> # 先按牌面值排序,再按照花色排序
>>> cards = [(6, "黑桃"), (5, "红桃"), (4, "方片"), (2, "梅花"),
         (7, "黑桃"), (8, "红桃"), (3, "方片"), (1, "梅花")]
>>> first = sorted(cards, key=lambda item: item[0])
>>> first
[(1, '梅花'), (2, '梅花'), (3, '方片'), (4, '方片'), (5, '红桃'), (6, '黑桃'), (7, '黑桃'), (8, '红桃')]
>>> second = sorted(first, key=lambda item: item[1])
>>> second
[(3, '方片'), (4, '方片'), (1, '梅花'), (2, '梅花'), (5, '红桃'), (8, '红桃'), (6, '黑桃'), (7, '黑桃')]

functools.cmp_to_key

在 Py2.x 版本中 sorted 函数的语法如下:

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

可以看到,Py2.x 中的 sorted 函数比 Py3.0 多了一个 cmp 参数。cmp 是一个可选参数,用于引入自定义比较函数。比较函数需要接受两个参数,并以正数、零和负数来表示两个参数的比较结果。例如:

def numeric_compare(x, y):
    """
    返回正数,表示x大于y;
    返回0,表示x等于y;
    返回负数,表示x小于y。
    """
    return x - y

在 Py2.x 中,我们可以通过 cmp 参数自定义排序函数:

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

但是,sorted 函数在 Py3.0 中该参数已移除了 cmp 参数。当我们将代码从 Py2.x 移植到 Py3.x 时,便需要将旧式比较函数(comparison function)转换为键函数(key function)。为了满足该需求,我们可以使用 functools.cmp_to_key() 函数。

cmp_to_key 函数用于将旧式比较函数(comparison function)转换为键函数(key function),在 Py3.2 中被引入。使用方式如下:

>>> # in Python 3
>>> def reverse_numeric(x, y):
...     return y - x
>>> sorted([5, 2, 4, 1, 3], key=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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容