资讯专栏INFORMATION COLUMN

由 sort 中 key 的用法浅谈 python

keke / 2601人阅读

摘要:但是实际写程序中,我们经常会写出许多繁杂的丑陋的代码。特别推荐,许多代码让我获益匪浅,比如这里对的使用。用可以写出很简单直观的代码,如下当然,上面不考虑效率,这里有一个利用分治法思想的高效的方法。更多文章更多阅读中参数的用法高级编程技巧

用 Python 时间也算不短了,但总感觉自己在用写 C++ 代码的思维写 Python,没有真正用到其作为脚本语言的优势。之前刷 LeetCode 时,自己的 Python 代码总是很长,很像披着 Python 外衣的 C++ 代码(放在这里,不断重构中)。

想来大概是因为觉得python简单,平时只是零零碎碎的学习,也没有去读别人的代码,导致掌握的不够深入。回想起前段时间的面试,面试官看我简历写熟悉Python,就问了两个Python的问题:

Python 中常用的优化技巧(能够提升 Python 执行效率的,除了算法层面)

按照 value 从小到大输出 dict 中的 key-value值。

我支支吾吾半天,就是没有答到点上,直接导致被拒(后来整理的内容放在这里)。所谓知耻而后勇,经过一段时间对 Python 的重新学习,才慢慢发现 Python 的一些强大与美妙之处。

从排序说起!

程序中经常用到排序函数,Python 提供了 sort 和 sorted 函数,一个原地排序,一个返回排序后的新结果,函数原型很简单:

sort([cmp[, key[, reverse]]])

自己用的最多的类似下面的语句:

>>> l = [43, 12, 4, 6]
>>> l.sort()
>>> l
[4, 6, 12, 43]

曾经窃以为这就体现了 Python 的简单优雅,不像 C++ STL中那样还需要指定迭代器范围,然后对 sort 的理解也就止步于此。后来遇到稍微复杂一点的排序场景,自己就 Google-Stackoverflow-Copy,解决了眼前的问题,但是从来没有去深挖(这也就导致那次面试中中没有回答出来上面的第二个问题)。

sort 之美

后来去看了下 sort 的函数说明,包括 cmp, key, reverse 参数究竟怎么去用,又写了几个例子,以为这下子对 sort 可谓是理解透彻了。比如要要根据值的大小输出字典内容,那么就可以像下面这样优雅地解决:

>>> d = {1: "z", 2:"y", 3: "x"}
>>> print sorted(d.items(), key=lambda x: x[1])
[(3, "x"), (2, "y"), (1, "z")]

我甚至可以得到一个根据value排序的字典,只需要用 collections.OrderedDict 即可:

>>> from collections import OrderedDict
>>> sorted_d = OrderedDict(sorted(d.items(), key=lambda x: x[1]))
>>> sorted_d
OrderedDict([(3, "x"), (2, "y"), (1, "z")])
sort 之魅

我以为我对 sort 理解足够了,直到在 hackerrank 遇到这个题目。

给定一个只包含大小写字母,数字的字符串,对其进行排序,保证:

所有的小写字母在大写字母前面

所有的字母在数字前面

所有的奇数在偶数前面

考虑用 sort 函数来完成排序。开始之前,再来看看文档对sort函数中key的说明:

key parameter to specify a function to be called on each list element prior to making comparisons. The value of the key parameter should be a function that takes a single argument and returns a key to use for sorting purposes.

通俗讲,key 用来决定在排序算法中 cmp 比较的内容,key 可以是任何可被比较的内容,比如元组(python 中元组是可被比较的)。所以上面的排序问题可以用下面的代码来解决:

>>> s = "Sorting1234"
>>> "".join(sorted(s, key=lambda x: (x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x)))
"ginortS1324"

这里,lambda 函数将输入的字符转换为一个元组,然后 sorted 函数将根据元组(而不是字符)来进行比较,进而判断每个字符的前后顺序。

如果同样的程序用 C++ 来写的话,可能需要一个复杂的仿函数,来定义排序的规则,远没有 Python 这般简洁优雅。

再探 Python

Python 是一门简单方便的语言,相信这是大部分人对 Python 的第一感觉。初学 Python,我们可能痴迷于 Python 的列表解析,list 切片,字典推导,或者是陶醉在各种强大的第三方库里,比如网络库 requests,科学计算库 numpy,web开发框架 Django 等。

但是实际写程序中,我们经常会写出许多繁杂的、丑陋的Python代码。比如要判断一个数字是否是回文数字,可能会习惯性地写出下面这样的代码:

def isPalindrome(x):
    if x < 0:
        return False
    reversed_x = 0
    original_x = x
    while x > 0:
        reversed_x = reversed_x * 10 + x % 10
        x /= 10
    return reversed_x == original_x

仔细一看,这简直就是 C++ 代码,完全没有 Python 的优雅与简单。那么,该怎样写才能够显的 Pythonic 呢?其实,用 Python 的话只要一行就可以啦(这里不考虑效率,如果考虑效率的话,C++会更加合适,单对这题来说,其实有比上面更高效的方法)!

def isPalindrome(x):
    return x >= 0 and str(x) == str(x)[::-1]

那么如何养成用 Pythonic 的思维解决问题呢?我觉得首先要对 Python 十分熟悉,精通大部分函数以及 Python 的特色:比如装饰器,迭代器,生成器以等,下面举几个简单的例子:

# 函数式编程
>>> nums = map(int, "123456789" )
>>> nums
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
15
>>> sum(nums)
45
# 生成器
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
...     print i
...
0
1
4
>>> for i in mygenerator:
...     print i
...
# lambda 匿名函数
>>> c = lambda *z: z
>>> c( 10, "test")
(10, "test")
# 迭代
>>> l = [i**2 for i in range(9)]
>>> l_iter = iter(l)
>>> next(l_iter)
0
>>> next(l_iter)
1
>>> next(l_iter)
4
# 数据结构 set
>>> set_a = set([i for i in range(1,9,2)])
>>> set_b = set([i for i in range(0,9,2)])
>>> print set_a | set_b
set([0, 1, 2, 3, 4, 5, 6, 7, 8])

其次,要多读一些 Pythonic 的代码,学习别人如何优雅地使用python。这里我推荐去看 Leetcode 的 Discuss,里面有许多惊才艳艳的代码。特别推荐 @StefanPochmann,许多代码让我获益匪浅,比如这里对 iter() 的使用。

再来看一个问题,按照二进制位反转 32 位的一个整形无符号数字。用 Python 可以写出很简单直观的代码,如下:

def reverseBits(n):
    bit_str = "{0:032b}".format(n)
    reverse_str = bit_str[::-1]
    return int(reverse_str, 2)

当然,上面不考虑效率,这里有一个利用分治法思想的高效的方法。

Python 是一门高效、简单、方便的语言,但这并不意味你不花时间就可以用的很好。

更多文章

更多阅读

Sorting Mini-HOW TO
sort()中cmp参数的用法
hackerrank: ginortS
Sort a Python dictionary by value
Python高级编程技巧

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/37896.html

相关文章

  • 浅谈 python sorted()与sort()

    摘要:返回值是一个经过排序的可迭代类型,与一样。注一般来说,和可以使用表达式。与的不同在于,是在原位重新排列列表,而是产生一个新的列表。 我们需要对List进行排序,Python提供了两个方法 对给定的List L进行排序,方法1.用List的成员函数sort进行排序方法2.用built-in函数sorted进行排序(从2.4开始) ----------------------------...

    lansheng228 评论0 收藏0
  • Python 进阶之路 (一) List 进阶方法汇总,新年快乐!

    摘要:尝射于家圃,有卖油翁释担而立,睨之,久而不去。康肃问曰汝亦知射乎吾射不亦精乎翁曰无他,但手熟尔。康肃忿然曰尔安敢轻吾射翁曰以我酌油知之。 开启变身模式 大家好, 从这一期开始,我们会从小白变身为中等小白,在基础起步阶段有太多的东西我没有讲到,但是俗话说的好,无他,但手熟尔,只要多多练习,时间会是最好的证明,相信我们终有一天会成为高手,因此从这一系列开始,让我们一起更上一层楼,还是和往常...

    garfileo 评论0 收藏0
  • Python进阶笔记

    摘要:用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。和不同的是,把传入的函数依次作用于每个元素,然后根据返回值是还是决定保留还是丢弃该元素。字符串给出当前平台使用的行终止符。程序中间的退出,为正常退出。 列表生成式 函数的参数类型 lambda函数 map, reduce, filter, sorted函数 eval, exec, join, zip函数 itertools中的...

    ygyooo 评论0 收藏0
  • 用了这么长时间python开发,你还记得多少零碎基础知识

    摘要:输出下标和对应的元素集合集合是无序的,集合中的元素是唯一的,集合一般用于元组或者列表中的元素去重。 python内置的数据类型 showImg(https://segmentfault.com/img/bVbrz1j); Python3.7内置的关键字 [False, None, True, and, as, assert, async, await, break, class, co...

    zollero 评论0 收藏0
  • Python 进阶之路 (二) Dict 进阶宝典,初二快乐!

    摘要:新年快乐大家好,今天是大年初二,身在国外没有过年的氛围,只能踏实写写文章,对社区做点贡献,在此祝大家新年快乐上一期为大家梳理了一些的进阶用法,今天我们来看字典的相关技巧,我个人在编程中对字典的使用非常频繁,其实对于不是非常大的数据存储需求, 新年快乐 大家好,今天是大年初二,身在国外没有过年的氛围,只能踏实写写文章,对社区做点贡献,在此祝大家新年快乐!上一期为大家梳理了一些List的进...

    ChristmasBoy 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<