2.1.3 列表推导式
列表推导式可以说是Python程序开发是应用最多的技术之一,列表推导式可以使用非常简洁的方式来快速生成满足特定需求的列表,代码具有非常强的可读性。另外,Python的内部实现对列表推导式做了大量优化,可以保证很快的运行速度。列表推导式形式为:
[ 表达式 for 变量 in 序列或迭代对象 ]
列表推导式在逻辑上相当于一个循环,只是形式更加简洁,例如:
1 >>> aList = [ x ** 2 for x in range(10) ]
2 >>> aList
3 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
相当于
1 >>> aList = []
2 >>> for x in range(10):
3 aList.append( x ** 2 )
4
5
6 >>> aList
7 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
8 >>>
当然也等价于
1 >>> aList = list(map(lambda x:x ** 2,range(10)))
2 >>> aList
3 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
4 >>>
再举个例子
1 >>> freshfruit = [' banana',' loganberry ','passion fruit ']
2 >>>
3 >>> aList = [ f.strip() for f in freshfruit ]
4 >>> aList
5 ['banana', 'loganberry', 'passion fruit']
6 >>>
7 >>> #等价于
8 >>> aList = []
9 >>> for f in freshfruit:
10 aList.append(f.strip())
11
12
13 >>> aList
14 ['banana', 'loganberry', 'passion fruit']
15 >>>
16 >>> #等价于
17 >>> aList = list(map(lambda x:x.strip(),freshfruit))
18 >>> aList
19 ['banana', 'loganberry', 'passion fruit']
20 >>>
小应用:一盘棋一共64个格子,在第一个格子放1粒米,第二个格子里放2粒米,第三个格子里放4粒米,第四个格子里放8粒米,以此类推,后面每个格子里的米都是前一个格子里的2倍,一直把64个格子都放满。一共需要多少粒米呢?
1 #方法一: 2 >>> a = [ 2 ** x for x in range(64) ] 3 >>> a 4 [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152,
4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296, 8589934592,
17179869184, 34359738368, 68719476736, 137438953472, 274877906944, 549755813888, 1099511627776, 2199023255552, 4398046511104,
8796093022208, 17592186044416, 35184372088832, 70368744177664, 140737488355328, 281474976710656, 562949953421312, 1125899906842624,
2251799813685248, 4503599627370496, 9007199254740992, 18014398509481984, 36028797018963968, 72057594037927936, 144115188075855872,
288230376151711744, 576460752303423488, 1152921504606846976, 2305843009213693952, 4611686018427387904, 9223372036854775808] 5 >>> 6 >>> sum(a) 7 18446744073709551615 8 9 10 #方法二: 11 >>> num = sum(list(map(lambda x:2 ** x,range(0,64)))) 12 >>> num 13 18446744073709551615 14 >>> 15 >>> 16 17 18 19 #方法三: 20 >>> b = [] 21 22 >>> 23 >>> for x in range(64): 24 b.append(2 ** x) 25 26 27 >>> b 28 [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304,
8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296, 8589934592, 17179869184,
34359738368, 68719476736, 137438953472, 274877906944, 549755813888, 1099511627776, 2199023255552, 4398046511104, 8796093022208,
17592186044416, 35184372088832, 70368744177664, 140737488355328, 281474976710656, 562949953421312, 1125899906842624, 2251799813685248,
4503599627370496, 9007199254740992, 18014398509481984, 36028797018963968, 72057594037927936, 144115188075855872, 288230376151711744,
576460752303423488, 1152921504606846976, 2305843009213693952, 4611686018427387904, 9223372036854775808] 29 >>> 30 >>> sum(b) 31 18446744073709551615 32 >>>
列表推导式应用系列:
1 使用列表推导式实现嵌套列表的平铺
1 >>> vec = [[1,2,3],[4,5,6],[7,8,9]]
2 >>>
3 >>> [ num for v in vec for num in v ]
4 [1, 2, 3, 4, 5, 6, 7, 8, 9]
5 >>>
6 >>> #步骤分解
7 >>> [ v for v in vec ]
8 [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
9 >>>
10 >>> vec
11 [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
12 >>> for v in vec:
13 print(v)
14
15
16 [1, 2, 3]
17 [4, 5, 6]
18 [7, 8, 9]
19 >>>
20 >>>
21 >>> #在这个列表推导式中有2个循环,其中第一个循环可以看作是外循环,执行得慢;而第二个循环可以看做是内循环,执行地快。
22 >>> #上述diamante等价于下面的写法:
23 >>>
24 >>> result = []
25 >>> for elem in vec:
26 for num in elem:
27 result.append(num)
28
29
30 >>> result
31 [1, 2, 3, 4, 5, 6, 7, 8, 9]
32 >>>
2 过滤不符合条件的元素
1 #在列表推导式中可以使用if子句来进行筛选,只在结果列表中保留符合条件的元素 2 #例如,下面的代码可以列出当前文件夹下所有Python源文件: 3 >>> import os 4 >>> 5 >>> [ filename for filename in os.listdir('.') if filename.endswith('.py') ] 6 7 ['hello.py'] #只有这一个文件 8 >>> 9 10 #下面的代码用于从列表中选择符合条件的元素组成新的列表: 11 >>> aList = [-1,-4,6,7.5,-2.3,9,-11] 12 >>> 13 >>> #需要过滤出列表中大于0的元素 14 >>> 15 >>> [ x for x in aList if x > 0 ] 16 [6, 7.5, 9] 17 >>> 18 19 #再例如,已知有一个包含一些同学成绩的字典,计算成绩的最高分、最低分、平均分,并查找所有最高分的同学,代码可以这样编写: 20 scores = { 21 "zhangsan":45, 22 "lisi":78, 23 "wangwu":40, 24 "zhouliu":96, 25 "zhaoqi":65, 26 "sunba":90, 27 "zhengjiu":78, 28 "wushi":99, 29 "dongshiyi":60 30 } 31 32 >>> highest = max(scores.values()) #最高分 33 >>> 34 >>> lowest = min(scores.values()) #最低分 35 >>> 36 >>> highest 37 99 38 >>> lowest 39 40 40 >>> 41 >>> average = sum(scores.values())/len(scores) #平均分 42 >>> average 43 72.33333333333333 44 >>> 45 >>> #找出哪位同学的成绩最高 46 >>> 47 >>> 48 >>> highestPerson = [ name for name,value in scores.items() if value == max(scores.values()) ] 49 >>> 50 >>> highestPerson 51 ['wushi'] 52 >>> 53 54 55 #下面的代码使用列表推导式查找列表中最大元素的位置 56 57 >>> from random import randint 58 59 >>> x = [ randint(1,10) for i in range(20) ] 60 >>> x 61 [10, 4, 4, 5, 8, 4, 5, 10, 4, 5, 7, 1, 7, 2, 10, 1, 10, 2, 4, 6] 62 >>> 63 >>> #第一步用enumetate处理x 64 >>> enumerate(x) 65 <enumerate object at 0x00000000037E4090> 66 >>> l = list(enumerate(x)) 67 >>> l 68 [(0, 10), (1, 4), (2, 4), (3, 5), (4, 8), (5, 4), (6, 5), (7, 10), (8, 4), (9, 5), (10, 7), (11, 1), (12, 7), (13, 2), (14, 10),
(15, 1), (16, 10), (17, 2), (18, 4), (19, 6)] 69 >>> 70 >>> ll = [ n for n,m in l if m == max(x)] 71 >>> ll 72 [0, 7, 14, 16] 73 >>>
3 在列表推导式中使用多个循环,实现多序列元素的任意组合,并且可以结合条件语句过滤特定元素
1 >>> [ (x,y) for x in [1,2,3] for y in [3,4,5] if x != y ]
2 [(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5)]
3 >>>
4
5
6 # 注意,对于包含多个循环的列表推导式,一定要清楚多个循环的执行顺序或“嵌套关系”。例如,上面的代码等价于:
7
8 >>> result = []
9 >>>
10 >>> for x in [1,2,3]:
11 for y in [3,1,4]:
12 if x != y:
13 result.append((x,y))
14
15
16 >>>
17 >>> result
18 [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
19 >>>
4 使用列表推导式实现矩阵转置
1 >>> # 下面的代码使用列表推导式实现矩阵转置:
2 >>> matrix = [[1,2,3,4],[5,6,7,8,],[9,10,11,12]]
3 >>>
4 >>> [[ row[i] for row in matrix] for i in range(4) ]
5 [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
6 >>>
7 >>> #或者可以是应用内置函数和zip()和list()来实现矩阵转置:
8 >>>
9 >>> list(map(list,zip(*matrix)))
10 [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
11 >>>
12 >>>
13 >>> matrix
14 [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
15 >>>
16
17
18 ##################### 还是作者的语句写得好啊,唉,我写出来的代码总是感觉很冗余。还是道行才浅了。
19 >>> a = zip(*matrix)
20 >>> a
21 <zip object at 0x0000000003517D88>
22 >>> list(a)
23 [(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
24 >>>
25 >>> b = [(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
26 >>>
27 >>> result = []
28 >>> for t in b:
29 result.append(list(t))
30
31
32 >>> result
33 [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
34 >>>
5 列表推导式中可以使用函数或复杂表达式
1 >>> #定义一个函数,参数如果为偶数就返回参数的平方,否则返回参数自增1的结果
2 >>> def f(v):
3 if v % 2 == 0:
4 v = v ** 2
5 else:
6 v = v + 1
7 return v
8
9 >>>
10 >>> l = [ f(v) for v in [2,3,4,-1] if v > 0]
11 >>> l
12 [4, 4, 16]
13 >>>
14 >>> #同样的也可用下边的方式实现
15 >>>
16 >>> ll = [ v ** 2 if v % 2 == 0 else v + 1 for v in [2,3,4,-1] if v > 0]
17 >>>
18 >>> ll
19 [4, 4, 16]
20 >>>
6 列表推导式支持文件对象迭代
1 >>> fp = open(r'C:\Users\dddd\Desktop\a.txt','r')
2 >>>
3 >>> l = [line for line in fp]
4 >>> l
5 ['Hello World!\n', 'I Love China !\n']
6 >>>
7 >>> fp.close()
8 >>> #手动关闭文件连接,释放系统资源。
9
10 #文件对象也是可迭代对象
7 使用列表推导式生成100以内的所有素数
1 >>> import math
2 >>>
3 >>> [ p for p in range(2,100) if 0 not in [ p % d for d in range(2,int(math.sqrt(p)) + 1 )]]
4
5 [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
6 >>>