Python 推导式是一种独特的数据处理方式,可以快速的从一个数据序列构建另一个新的数据序列的结构体。
如:要把[1,2,3,4]的列表转换为[2,4,6,8]的列表,我们可以用下面的代码实现:
lst = [1,2,3,4]
lst2 = []
for i in lst:
res = i * 2
lst2.append(res)
print(lst2)
在python中,为了更简洁、优雅的进行这种变换,使用一种新的语法来实现,如上面的例子,用推导式可以改写为:
lst = [1,2,3,4]
lst2 = [ x*2 for x in lst]
print(lst2) #[2, 4, 6, 8]
推导式的基本格式为:
表达式 for 变量 in iterable(可迭代对象)
或者
表达式 for 变量 in iterable(可迭代对象) if 条件
根据结果集的不同,推导式可以分为:
- 列表推导式
- 元组推导式
- 字典推导式
- 集合推导式
列表推导式
列表推导式使用很频繁,也称为列表解释式、for表达式,其作用使用一种优雅的形式来创建列表
简单列表推导式
基本语法为:
[表达式 for 变量 in 列表] [out_exp_res for out_exp in input_list]
- out_exp_res:列表生成元素表达式,可以是有返回值的函数。
- for out_exp in input_list:迭代 input_list 将 out_exp 传入到 out_exp_res 表达式中。
说明:列表推导式从左到右一次递进,语句之间有嵌套关系
例如:
nums = [x for x in range(1,9)]
print(nums) #[1, 2, 3, 4, 5, 6, 7, 8]
列表推导式可以看成:
for 迭代变量 in 可迭代对象
表达式
如上面的可以改写为:
nums = []
for x in range(1,9):
nums.append(x)
带表达式的推导式
前面的表达式不仅可以是单变量,也可以是复杂的表达式,如:
# 每个元素 - 1
nums = [x - 1 for x in range(1, 9)]
print(nums) #[0, 1, 2, 3, 4, 5, 6, 7]
# 每个元素 * 2
nums = [x - 1 for x in range(1, 9)]
print(nums) #[0, 1, 2, 3, 4, 5, 6, 7]
# 每个元素 * 2
nums = [x * 2 for x in range(1, 9)]
print(nums) #[2, 4, 6, 8, 10, 12, 14, 16]
# 每个元素 * 元素
nums = [x * x for x in range(1, 9)]
print(nums) #[1, 4, 9, 16, 25, 36, 49, 64]
b_list = [x * x for x in a_range if x % 2 == 0]
# a_list集合包含5个元素
print(b_list) #[0 ,4 , 16, 36, 64]
strings = ['Hello', 'World', 'In', 'Python']
lowercase_strings = [s.lower() for s in strings]
print(lowercase_strings) # Output: ['hello', 'world', 'in', 'python']
过滤列表推导式
语法为:
[表达式 for 变量 in 列表 if 条件] [out_exp_res for out_exp in input_list if condition]
- out_exp_res:列表生成元素表达式,可以是有返回值的函数。
- for out_exp in input_list:迭代 input_list 将 out_exp 传入到 out_exp_res 表达式中。
- if condition:条件语句,可以过滤列表中不符合条件的值。
# 求1~55被5整除的数
nums = [x for x in range(1, 56) if x % 5 == 0]
print(nums) #[5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55]
# 求1~55被5整除的数,再除5
nums = [x // 5 for x in range(1, 56) if x % 5 == 0]
print(nums) #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
嵌套推导式
推导式支持多个变量的嵌套:
语法为:
[ expression for item in iterable if condition for sub_item in sub_iterable if sub_condition ]
d_list = [(x, y) for x in range(5) for y in range(4)]
# d_list列表包含20个元素
print(d_list)
‘’'
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3), (3, 0), (3, 1), (3, 2), (3, 3), (4, 0), (4, 1), (4, 2), (4, 3)]
‘''
lst1 = ["one","two","three","four"]
lst2 = ["five","six","seven","eight"]
res = [ i +"♥♥♥"+j for i in lst1 for j in lst2 ]
print(res)
‘’'
['one♥♥♥five', 'one♥♥♥six', 'one♥♥♥seven', 'one♥♥♥eight', 'two♥♥♥five', 'two♥♥♥six', 'two♥♥♥seven', 'two♥♥♥eight', 'three♥♥♥five', 'three♥♥♥six', 'three♥♥♥seven', 'three♥♥♥eight', 'four♥♥♥five', 'four♥♥♥six', 'four♥♥♥seven', 'four♥♥♥eight']
‘''
上面代码中,x 是遍历 range(5) 的迭代变量(计数器),因此该 x 可迭代 5 次;y 是遍历 range(4) 的计数器,因此该 y 可迭代 4 次。因此,该(x,y)表达式一共会迭代 20 次。上面的 for 表达式相当于如下嵌套循环:
dd_list = []
for x in range(5):
for y in range(4):
dd_list.append((x, y))
当然,也支持类似于三层嵌套的 for 表达式,例如如下代码:
e_list = [[x, y, z] for x in range(5) for y in range(4) for z in range(6)]
# e_list列表包含120个元素
print(e_list)
‘’'
[[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 0, 3], [0, 0, 4], [0, 0, 5], [0, 1, 0], [0, 1, 1], [0, 1, 2], [0, 1, 3], [0, 1, 4], [0, 1, 5], [0, 2, 0], [0, 2, 1], [0, 2, 2], [0, 2, 3], [0, 2, 4], [0, 2, 5], [0, 3, 0], [0, 3, 1], [0, 3, 2], [0, 3, 3], [0, 3, 4], [0, 3, 5], [1, 0, 0], [1, 0, 1], [1, 0, 2], [1, 0, 3], [1, 0, 4], [1, 0, 5], [1, 1, 0], [1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 1, 4], [1, 1, 5], [1, 2, 0], [1, 2, 1], [1, 2, 2], [1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 3, 0], [1, 3, 1], [1, 3, 2], [1, 3, 3], [1, 3, 4], [1, 3, 5], [2, 0, 0], [2, 0, 1], [2, 0, 2], [2, 0, 3], [2, 0, 4], [2, 0, 5], [2, 1, 0], [2, 1, 1], [2, 1, 2], [2, 1, 3], [2, 1, 4], [2, 1, 5], [2, 2, 0], [2, 2, 1], [2, 2, 2], [2, 2, 3], [2, 2, 4], [2, 2, 5], [2, 3, 0], [2, 3, 1], [2, 3, 2], [2, 3, 3], [2, 3, 4], [2, 3, 5], [3, 0, 0], [3, 0, 1], [3, 0, 2], [3, 0, 3], [3, 0, 4], [3, 0, 5], [3, 1, 0], [3, 1, 1], [3, 1, 2], [3, 1, 3], [3, 1, 4], [3, 1, 5], [3, 2, 0], [3, 2, 1], [3, 2, 2], [3, 2, 3], [3, 2, 4], [3, 2, 5], [3, 3, 0], [3, 3, 1], [3, 3, 2], [3, 3, 3], [3, 3, 4], [3, 3, 5], [4, 0, 0], [4, 0, 1], [4, 0, 2], [4, 0, 3], [4, 0, 4], [4, 0, 5], [4, 1, 0], [4, 1, 1], [4, 1, 2], [4, 1, 3], [4, 1, 4], [4, 1, 5], [4, 2, 0], [4, 2, 1], [4, 2, 2], [4, 2, 3], [4, 2, 4], [4, 2, 5], [4, 3, 0], [4, 3, 1], [4, 3, 2], [4, 3, 3], [4, 3, 4], [4, 3, 5]]
‘''
带条件的列表推导式如下:
字符串也是列表:
list1 = [x for x in 'OpenAI']
print(list1) #['O', 'p', 'e', 'n', 'A', 'I']
#双遍历字符相加
list1 = [x + y for x in 'OpenAI' for y in '01']
print(list1) #['O0', 'O1', 'p0', 'p1', 'e0', 'e1', 'n0', 'n1', 'A0', 'A1', 'I0', 'I1']
对于包含多个循环的 for 表达式,同样可指定 if 条件。假如我们有一个需求:程序要将两个列表中的数值按“能否整除”的关系配对在一起。比如 src_a 列表中包含 30,src_b 列表中包含 5,其中 30 可以整除 5,那么就将 30 和 5 配对在一起。对于上面的需求使用 for 表达式来实现非常简单,例如如下代码:
src_a = [30, 12, 66, 34, 39, 78, 36, 57, 121]
src_b = [3, 5, 7, 11]
# 只要y能整除x,就将它们配对在一起
result = [(x, y) for x in src_b for y in src_a if y % x == 0]
print(result)
‘’'
[(3, 30), (3, 12), (3, 66), (3, 39), (3, 78), (3, 36), (3, 57), (5, 30), (11, 66), (11, 121)]
‘''
嵌套列表推导式
列表推导式还可以嵌套使用,处理更复杂的数据结构,比如我们要将一个嵌套列表展平:
nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened_list = [x for sublist in nested_list for x in sublist]
print(flattened_list) # Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]
将一个二维的嵌套列表展平成了一维列表,就像是将多层次的数据展开,方便我们进行后续处理。
使用列表推导式实现全排列:
perms = [(x, y, z) for x in range(3) for y in range(3) for z in range(3) if x != y and y != z and x != z]
print(perms) # Output: [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
这个例子通过列表推导式生成了 3 个元素的全排列,使用了嵌套循环和条件判断,非常简洁而高效。
元组推导式
元组推导式可以利用 range 区间、元组、列表、字典和集合等数据类型,快速生成一个满足指定需求的元组。
元组推导式基本格式:
(表达式 for item in Sequence ) 或 (expression for item in Sequence if conditional )
元组推导式和列表推导式的用法也完全相同,只是元组推导式是用 () 圆括号将各部分括起来,而列表推导式用的是中括号 [],另外元组推导式返回的结果是一个生成器对象。如果要像列表推导式一样使用,需要在括号前加tuple进行类型说明:
num = (x for x in range(0,5))
print(num) #<generator object <genexpr> at 0x000001F2B72C70B0>
num = tuple((x for x in range(0,5)))
print(num) #(0, 1, 2, 3, 4)
字典推导式
基本格式为:
{ key_expr: value_expr for value in collection } 或 { key_expr: value_expr for value in collection if condition }
dict1 = {x:x*x for x in range(1,5)}
print(dict1)#{1: 1, 2: 4, 3: 9, 4: 16}
list1 = ['openai','pyth','on']
dict1 = {key:len(key) for key in list1}
print(dict1) #{'openai': 6, 'pyth': 4, 'on': 2}
可以使用下面方法把对已有的字典进行变换:
dict1 = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
#把字典值变大3倍
triple_dict1 = {k:v*3 for (k,v) in dict1.items()}
print(triple_dict1) #{'a': 3, 'b': 6, 'c': 9, 'd': 12, 'e': 15}
也可以简单的方法获取字典的健或值:
获取字典中所有的键:
{key for key in data} # {'key', '键'}
或
{key for key in data.keys()} # {'key', '键'}
获取字典中所有的值
{value for value in data.value()} # {'值', 'value'}
获取字典中所有的键和值
{key: value for key, value in data.items()} # {'key': 'value', '键': '值'}
交换字典中的键和值
{value: key for key, value in data.items()} # {'value': 'key', '值': '键'}
集合推导式
集合推导式基本格式:
{ expression for item in Sequence } 或 { expression for item in Sequence if conditional }
集合推导式与列表推导式基本相同,只是使用了大括号而不是方括号。
# 生成1到10的平方数集合
squares = {x ** 2 for x in range(1, 11)}
print(squares) #{64, 1, 4, 36, 100, 9, 16, 49, 81, 25} #注意集合是无序的
高级应用场景
复杂条件
求所有在100到1000之间的水仙花数,水仙花数定义:指一个正整数的各位数字的立方和等于其本身。
>>> for i in range(100,1000):
if i==(i //100)**3 + (i//10%10)**3 + (i%10)**3:
print(i, end=' ')
153 370 371 407
>>>
>>> # 改写成列表推导式:
>>> [i for i in range(100,1000) if i==(i //100)**3 + (i//10%10)**3 + (i%10)**3]
[153, 370, 371, 407]
>>>
与统计函数结合
1000~2021中包含7的数字有多少:
sum([1 for i in range(1000,2022) if '7' in str(i)]) #273
1000~2021中“包含7且能被7整除”的数字有多少:
sum([1 for i in range(1000,2022) if '7' in str(i) and i%7==0]) #39
与lambda函数结合
小于1000000的所有正整数一共包含有多少个数字“7”
num=lambda n:sum([str(i).count('7') for i in [i for i in range(1,n+1)] if '7' in str(i)])
num(999999) #600000,if '7' in str(i) 可省掉,即0也合计结果一样
一维二维列表间的转换
a=list(range(1,10))
print(a) #[1, 2, 3, 4, 5, 6, 7, 8, 9]
b=[a[i:i+3] for i in range(0,len(a),3)] #一维转化为二维
print(b) #[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
c=[j for i in b for j in i] #二维拉平为一维
print(c) #[1, 2, 3, 4, 5, 6, 7, 8, 9]
print(sum(b,[])) #[1, 2, 3, 4, 5, 6, 7, 8, 9]
二维表的转置
行列互换,首行变首列,尾行变尾列,如下所示:
>>> arr=[[1,2,3], [4,5,6], [7,8,9]]
>>> [[arr[i][j] for i in range(len(arr))] for j in range(len(arr[0]))]
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
>>>
求矩阵的乘积
#求M,N中矩阵和元素的乘积
M = [[1,2,3], [4,5,6], [7,8,9]]
N = [[2,2,2], [3,3,3], [4,4,4]]
res = [[M[i][j]*N[i][j] for j in range(len(M))] for i in range(len(N))]
print(res)
‘’’
[[2, 4, 6], [12, 15, 18], [28, 32, 36]]
’‘’
与enumerate()结合
enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标。 也就是说,对于一个可迭代的(iterable)/可遍历的对象(如列表、字符串),enumerate将其组成一个索引序列,利用它可以同时获得索引和值。 语法格式如下: enumerate(sequence[,startindex=0])
参数
- sequence -- 一个序列、迭代器或其他支持迭代对象。
- start -- 下标起始位置。
>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1)) # 下标从 1 开始
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
season=['spring','summer','fall','winter']
print(enumerate(season)) #<enumerate object at 0x000002CE4C2EC870>
print(list(enumerate(season))) #[(0, 'spring'), (1, 'summer'), (2, 'fall'), (3, 'winter')]
for i in enumerate(season):
print(i)
‘’’
(0, 'spring')
(1, 'summer')
(2, 'fall')
(3, 'winter’)
’‘’
for i,element in enumerate(season):
print(i,season[i])
print(i)
‘’’
0 spring
0
1 summer
1
2 fall
2
3 winter
3
’‘’
上面的例子enumerate()的对象参数是一个列表,但enumerate可不仅仅如此,文档上解释是对可遍历的对象均可用enumerate,这其中也包括字符串:
abc='abcdefg'
print(enumerate(abc)) #<enumerate object at 0x000001B75A712828>
print(list(enumerate(abc))) #[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e'), (5, 'f'), (6, 'g')]
for i in enumerate(abc):
print(i)
‘’’
(0, 'a')
(1, 'b')
(2, 'c')
(3, 'd')
(4, 'e')
(5, 'f')
(6, 'g’)
’‘’
for i,element in enumerate(abc):
print(i,abc[i])
‘’’
0 a
1 b
2 c
3 d
4 e
5 f
6 g
’‘’
100-1000中的数中,数等于各位数字的立方和的数:
>>> >>> for i in range(100,1000):
k=0
for j in str(i):
k+=int(j)**3
if k==i:
print(i,end=' ')
153 370 371 407
>>>
>>> # 转成列表推导式:
>>> [n for i,n in enumerate([sum([int(i)**3 for i in str(j)]) for j in range(100,1000)]) if i+100==n]
[153, 370, 371, 407]
>>>
from collections import Iterator
lst = ['东', '南', '西', '北']
# 基本使用
it = enumerate(lst) # 实现功能返回迭代器
print(isinstance(it, Iterator)) # True
# 强转成列表
new_lst = list(it)
print(new_lst) # [(0, '东'), (1, '南'), (2, '西'), (3, '北')]
"""
可以看到里面的元列表中的数据和对应的索引号码一一对应成了元组
"""
上面的举例当中,如果使用字典推导式和enumerate函数配合,就可以用一句话达成组成一个字典的目的。
from collections import Iterator
lst = ['东', '南', '西', '北']
# enumerate 配合使用字典推导式 变成字典
dct = {k: v for k, v in enumerate(lst)}
print(dct) # {0: '东', 1: '南', 2: '西', 3: '北'}
与zip()结合
zip()将多个Iterable中的值,一个一个拿出来配对组成元组放入迭代器中,如果某个元素多出,没有匹配项就会被舍弃。
语法格式为:
zip(iterable, iterable1, ……)
参数就是一个个的可迭代对象。
返回值:迭代器
lst1 = [1, 2, 3, 4, 5]
lst2 = ['a', 'b', 'c', 'd']
lst3 = ['A', 'B', 'C']
it = zip(lst1, lst2, lst3)
lst = list(it)
print(lst) # [(1, 'a', 'A'), (2, 'b', 'B'), (3, 'c', 'C')]
利用zip实现字典推导式
fruits = ['apple', 'banana', 'orange']
prices = [10,8,4]
res ={n:p for n,p in zip(fruits, prices)}
print(res) #{'apple': 10, 'banana': 8, 'orange': 4}
使用dict强转迭代器
res2 = dict(zip(fruits, prices))
print(res2) #{'apple': 10, 'banana': 8, 'orange': 4}
dict1 = {'apple': 10, 'banana': 8, 'orange': 4}
dict2 = {'peach': 20, 'plum': 30, 'cherry': 50}
keys1 = dict1.keys()
values2 = dict2.values()
#使用dict强转迭代器实现
new_dict = dict(zip(keys1, values2))
print(new_dict) #{'apple': 20, 'banana': 30, 'orange': 50}
#使用字典推导式实现
new_dict2 = {k:v for k,v in zip(keys1, values2)}
print(new_dict2) #{'apple': 20, 'banana': 30, 'orange': 50}