一. 使用列表推导,而不是 map 和 filter
列表推导不需要编写额外的 lambda
表达式,因此使用列表推导要比内置的 map
filter
函数更加清晰。如下面的列子,同样是将一个列表中的元素取平方,返回一个新的列表:
>>> l = list(range(10))
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [i**2 for i in l]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> list(map(lambda x: x**2, l))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
此外,如果还需要对原列表中的元素进行过滤,那列表推导的优势将进一步体现,因为列表推导只需在循环后面添加条件表达式,即可直接过滤原列表的元素;而 map
则必选结合 filter
函数。如下面的例子,我们在求平方前需要过滤掉偶数项:
>>> [x** 2 for x in l if x%2 == 0]
[0, 4, 16, 36, 64]
>>> list(map(lambda x: x**2, filter(lambda x: x%2 == 0, l)))
[0, 4, 16, 36, 64]
最后,我们需要了解一下,除了列表推导,字典和集合也支持推导表达式:
>>> students = {1:'alex', 2:'bob', 3:'christian', 4:'dana', 5:'eartha'}
>>> students
{1: 'alex', 2: 'bob', 3: 'christian', 4: 'dana', 5: 'eartha'}
>>> {str(index*100)[::-1]:name.capitalize() for index, name in students.items()}
{'001': 'Alex',
'002': 'Bob',
'003': 'Christian',
'004': 'Dana',
'005': 'Eartha'}
>>> {len(name) for name in students.values()}
{3, 4, 6, 9}
二. 在列表推导中,请避免使用 2 个以上的表达式
列表推导除了上述的基本用法之外,还支持多重循环。如下面的例子,我们把二维矩阵简化为一维矩阵。先以 numpy
的 ndarray
说明目的:
>>> import numpy as np
>>> arr = np.arange(1,10).reshape(3,3)
>>> arr
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
>>> arr.flatten()
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
下面,我们将一个 2 维列表也像这样拉平成 1 维,采用包含 2 个 for
表达式的列表推导即可:
>>> my_list = arr.tolist()
>>> my_list
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> [x for row in my_list for x in row]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
上面的例子简单易懂,下面再演示一种包含多重循环的合理用法,下面我们对 2 维列表中的每个元素求平方。 同样先以 numpy ndarray
来说明目的:
>>> arr**2
array([[ 1, 4, 9],
[16, 25, 36],
[49, 64, 81]], dtype=int32)
ndarray
可以直接进行矢量运算,非常简单。因为还是只包含 2 个循环,所以列表的实现也不复杂,很容易理解:
>>> [[x**2 for x in row] for row in my_list]
[[1, 4, 9], [16, 25, 36], [49, 64, 81]]
列表推导也支持多个 if
条件,处在同一循环级别中的多项条件,彼此之间默认形成 and
表达式。比如下面的例子,从列表中选出大于 5 的偶数:
>>> my_list = list(range(1,10))
>>> my_list
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [x for x in my_list if x > 5 and x % 2 == 0 ]
[6, 8]
>>> [x for x in my_list if x > 5 if x % 2 == 0 ]
[6, 8]
比如,下面的例子,就非常的复杂,阅读代码的其他人很难理解。这里只列出演示过程,就不具体讲解啦,有兴趣的同学可以自己推敲一下,但请不要在你的项目中写出如此复杂的列表推导,会增加后期其他开发人员的维护成本。
>>> arr
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
>>> my_arr = arr[np.newaxis,:]
>>> my_arr
array([[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]])
>>> my_list = my_arr.tolist()
>>> my_list
[[[1, 2, 3], [4, 5, 6], [7, 8, 9]]]
>>> flat = [x for sublist1 in my_list for sublist2 in sublist1 for x in sublist2]
>>> flat
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> my_list_2 = arr.tolist()
>>> my_list_2
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> filtered = [[x ** 2 for x in row if x % 3 == 0] for row in my_list_2 if sum(row) > 10]
>>> filtered
[[36], [81]]