新手再提问关于 list 排序

2014-08-08 18:55:44 +08:00
 Eyon
lst = [['lucy','25','beijing'],['lilei','32','hongkong'],['hanmeimei','9','sichuan'],['tom','13','shanghai']]

请问如何按照年龄对这几个人的列表进行排序(数字为年龄)

3121 次点击
所在节点    Python
18 条回复
yingluck
2014-08-08 18:59:19 +08:00
lst.sort(key=lambda i: int(i[1]))
Eyon
2014-08-08 19:04:02 +08:00
@yingluck 话说没看懂,换一种问法。如果我想按照地名排序呢:(beijing、shanghai、hongkong、sichuan)
yingluck
2014-08-08 19:18:04 +08:00
pos_dict = {'beijing':0, 'shanghai':1, 'hongkong':2, 'sichuan':3}
lst.sort(key=lambda i: pos_dict[i[2]])

上网搜列表排序 有真相
ccdjh
2014-08-08 19:20:27 +08:00
添加了int,是因为排列数字的时候,如果是字符串,排列会出现 '13' '25' '32' '9'

int后,才是 9 13 25 32
Eyon
2014-08-08 19:21:29 +08:00
@ccdjh 嗯,他这一点我看懂了。只是 lambda 函数不懂。
fishsjoy
2014-08-08 19:42:00 +08:00
sort按照key函数返回的值排序。针对lst里的每一项, 调用lambda函数来返回排序依据。
geeti
2014-08-09 09:43:52 +08:00
@Eyon key就是一个函数,用来处理所需要排序的元素,返回排序的关键词
Eyon
2014-08-09 11:05:21 +08:00
@yingluck

貌似无效!


@geeti key 确实是一个函数,但是我没有明白的是函数本身并没有“顺序”可言,为什么需要依赖它来排序呢。
kevinyoung
2014-08-09 11:48:02 +08:00
@Eyon 你给的截图就是按照地名(beijing、shanghai、hongkong、sichuan)排序的结果没错啊。

关于排序时key这个东西,默认情况下是None,那么排序依据是系统默认的那一套,比如lz给出的列表默认排序的话是按照每一个子列表的第一个元素的先后顺序来的。

如果想自己指定排序规则,就需要显式地给出关键字参数key=f,其中f必须是一个函数。比如我们要对[item1, item2, item3]排序(注意这里的items可以是任何东西),在指定了key之后系统先将待排序的列表的每一个元素传递进f中,得到一个由返回值组成的列表[f(item1), f(item2), f(item3)],并对这个返回值列表进行排序,排序完了再把每个返回值替换会初始值就是最终结果了。当然上面只是打个比方,python实际上可能不是这么干的。

关于lambda,lambda是匿名函数的关键字。前面说到必须用一个函数给key赋值,比如按照一楼给出的lst.sort(key=lambda i: int(i[1]))按照年龄排序,你完全可以这样写:

def get_age(person):
age = person[1]
return int(age)
lst.sort(key=get_age)

这里的get_age函数和lambda i: int(i[10])是等价的,你应该也看明白了,对于lambda函数,i就是参数,冒号后面的一坨是返回值。用lambda的好处是不必给函数起名字,方便省事可读性好,尤其适用于map,reduce,sorted(请查看官方文档builtin function部分)这样以函数为参数的高阶函数,习惯后就离不开了。
geeti
2014-08-09 12:28:53 +08:00
@Eyon 没明白你加一个dict干嘛
lambda i:i[2] 不就行了
Eyon
2014-08-09 15:30:01 +08:00
@kevinyoung 非常感谢你的回复,如果大家都能够这样讨论,那新手将会成长的很快。
我目前还没有搞清楚函数在此存在的意义(除了 key=后面跟函数之外),因为就我目前所理解的,函数必须要调用才有意义,而函数中定义的变量也需要赋值才有意义。比如我定义一个函数

def f(x):
return x

在使用时:

y = 1

print f(y)才等于1,这样给"变量"赋值之后,函数 f 和才有异议

而在你给的这个函数:
def get_age(person):
age = person[1]
return int(age)
lst.sort(key=get_age)

中,并没有给 person 赋值的步骤(虽然我知道表面上它看起来指向了一个人),我不知道他怎么就与一个人关联上了,如果说像下面这样写,我还能懂:

def get_age(person):
person = lst[i][1] #这里假设 i 已经用 for 循环求出值了
age = person[1]
return int(age)
lst.sort(key=get_age)

也就是说,我没有搞清楚 person 是如何和人名或者说人名所在的字典扯上关系的,这是目前我很不解的地方。你能再解答一下吗?
pandada8
2014-08-10 08:06:17 +08:00
@Eyon Python中函数名可以作为参数互相传来传去

def p(param):
____print(param)

def q(a,func):
____func(a)


q('helloworld',p)
kevinyoung
2014-08-10 14:29:07 +08:00
@Eyon 我觉得你可能有一些过程式编程的底子,而这里讨论的sort方法则有函数式编程的意味,所以给你造成了一些困扰,下面我试着解释一下。

python本身包含深广,除了显见的过程式和面向对象思想以外,Guido也借鉴了一些他认为的函数式编程里面好的思想,与这里的问题相关的也是比较重要的一个就是:函数在python里面是first class的,和其他的变量啦、对象啦一样,是一等公民,当然这术语你可以不必理会,只需要知道对于函数f,你可以f()调用,可以g=f赋值,也可以把f当成是参数传递给其他函数,甚至可以把f当成一个函数的返回值返回出来。

下面回到问题本身,list的sort方法可以接收一个函数作为参数,上面的lst.sort(key=get_age)就是把get_age这个函数作为参数传递进sort中去了。

而且lz你的理解是正确的,函数只有被调用之后才有意义,只是这里的调用不是显式进行的,而是由系统帮你完成的。至于是如何完成的,下面可能要绕一个弯子。

sort这个函数稍微复杂一些,我想换一个类似但简单一些的例子,也就是python的另一个内置函数map,如果你能理解map,sort就不成问题了,而且在实战中map的用途也更为广泛。map的官方解释在此https://docs.python.org/2/library/functions.html#map ,其实已经介绍的很详细了,但我知道一开始还是很难接受,没事,接着看。map的函数签名是map(function, iterable),他的第一个参数是一个函数,第二个参数是一个可迭代对象,典型的例子就是列表,再看map的返回值,比如我调用:

map(f, [item1, item2, item3])

将返回:

[f(item1), f(item2), f(item3)]

那lz你会说,在哪儿调用的呢?当然在map函数的实现中了,下面可以写一个乞丐版的map实现:

def map(func, iterable):
____result = []
____for item in iterable:
________result.append(func(item))
____return result

python的标准库实现要复杂的多,但本质上就是这样。上面的map实现,就是lz更加熟悉的过程式编程了,而直接调用map(f, iters)则有函数式编程的意味,注意两者的区别:前者关注的是如何完成这件事,后者关注的是干了什么。

那么为什么要用函数式编程呢?因为它更短更易读,所以出错的机会少。lz可能会说,明明是for循环更易读啊,那只是你看的多习惯了而已。近年来的高级语言有一个趋势,就是试图消除for循环,而用诸如map这样的高阶函数来取代。lz在学习python的过程中势必有一天要回过头去,将你以前的代码用高阶函数重写,那时你的技艺也会提升一个等级。

好像扯远了,我们回到sort上来。这里的sort是lst的一个方法,如果lz你知道类怎么写的话就知道在列表类的定义中,sort方法默认的第一个参数是self,也就是lst自己,所以lst.sort(key=f)本质上就是sort(lst, key=f),是不是和上面的map很像,在背后的实现中当然也有类似map的将f分别作用于lst的每个元素,并得到一个返回值,然后根据返回值进行排序,再将排序好的列表返回出来,具体的实现就不写了。
ClutchBear
2014-08-11 19:02:36 +08:00
[img] [/img]
这样就容易理解了吧.
lambda就是自定义函数的简写.
Eyon
2014-08-11 22:45:47 +08:00
@ClutchBear

嗯,关于 lambda 有一点点入门了,我目前的理解是:凡是需要返回变量本身的函数,就用 lambda....当然我觉得我这个理解有很大的问题。

但即使对于你写的这个传统函数,仍然有一个“指向性”的问题没搞懂。为了更好的描述我的困惑,我把函数这样写:



从这个运行结果来看,i[1] 其实等于 lst[1]所获得得值——['lilei', '32', 'hongkong']。但是从你写的函数来看,显然i[1]又等于是 lst[i][1]的值。

也就是说,为什么在这个函数中,i[1] 就直接指向了一个年龄(数字),而不是指向 lst 列表的第一个元素 lst[1]呢?
Eyon
2014-08-11 22:47:04 +08:00
@kevinyoung 今天没有时间翻书,我打算先掌握 map 和迭代的具体含义之后,看能不能理解。非常谢谢你。
ClutchBear
2014-08-12 00:11:23 +08:00
@Eyon 因为函数age的参数是lst列表的元素,不是列表本身.
也就是,应该这样来显示才行.
Eyon
2014-08-12 08:45:41 +08:00
@ClutchBear 貌似懂了,谢谢。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/126834

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX