Python 列表解析与生成器表达式

Python 的强大特性之一是其对 list 的解析,它提供一种紧凑的方法,可以通过对 list 中的每个元素应用一个函数,从而将一个 list 映射为另一个 list。
列表解析,又叫列表推导式( List comprehension)
列表解析比 for 更精简,运行更快,特别是对于较大的数据集合
列表解析可以替代绝大多数需要用到 map和 filter的场合

列表解析式是将一个可迭代对象(如列表)转换成另一个列表的工具。在转换过程中,可以指定元素必须符合某一条件,并按照指定的表达式进行转换,才能添加至新的列表中。

列表解析(List comprehensions)

语法:

[expression for iter_var in iterable1]

[expression for iter_var2 in iterable2 …
for iter_varN in iterableN]

[expression for iter_var in iterable1
if condition]
执行

迭代iterable中所有的元素,每一次迭代都把iterable中的内容放到iter_var对象中,然后把这个对象应用到表达式expression中,生成一个列表。
Python 列表解析与生成器表达式_第1张图片
简单来说,列表解析(list comprehension)提供了一种优雅的生成列表的方法,能用一行代码代替十几行代码,而且不损失任何可读性。而且,性能还快很多很多

例1,如果我们需要0~100所有偶数组成的列表
正常的代码应该是这样的:

a=[]
for i in range(101):
    if i%2==0:
        a.append(i)

用列表解析来做就是这样的:

a=[x for x in range(101) if x%2==0]

简单的一行代码代替了4行代码

从上面的例子来看列表解析的语法其实不难,可以分成三个部分来看

x:我们需要的列表里面的结果(1st part)
for x in range(101):x来源——0~100的数字(2nd part)
if x%2==0:x成立的条件,如果不成立就不放在列表里了(3rd part)

例2,获取文本中所有单词的第1个字符

正常的代码

text="My house is full of flowers"
first_charts=[]
for word in text.split():
    first_charts.append(word[0])

列表解析的代码:

first_charts=[word[0] for word in text.split()]

从上面的这个例子可以看出,列表解析的第一部分也可以是任意一个表达式

例3,获取两个列表对应位的乘积

来个复杂的,list a=[2,3,4,5]; list b=[3,4,5,6],想要得到a,b对应位的乘积:

[i*j for i,j in zip(a,b)]

除了列表解析,还需要使用zip函数来帮忙,zip将a,b对应位打包起来,返回[[2,3][3,4][4,5][5,6]]

例4,带if else的列表解析

list a=[‘1’,‘2’,‘3’,‘i’,‘8’],现在想将a中所有能转化为数字的字符串转化为数字,不为数字的内容都转换成0,用列表解析可以这样写:

[int(i) if i.isdigit() else 0 for i in a]
out>>[1,2,3,0,8]

增加一点难度,如果list a=[‘1’,‘2’,‘3’,4,5,‘o’,‘6’],如果不能转换成数字则为None,列表解析可以这样写:

[int(i) if str(i).isdigit() else None for i in a]
out>>[1, 2, 3, 4, 5, None, 6] 

从这个例子我们可以看到,在第一个部分,可以嵌套若干if else的语句在表达式里面。

例5,获取一个全0列表

有时候我们可能需要获取一个长度指定,全零或者全为某个值列表:

['ok' for i in range(10)]

得到一个长度为10的,全’ok’字符组成的列表。

例6,略复杂的列表解析,获取列表中嵌套列表的元素,生成一个无嵌套的新列表

这个例子说起来挺拗口,实际上是想从[[1,2],[3,4,5],[6,7],[8]]这种列表中,把嵌套在列表中的元素解出来,得到[1,2,3,4,5,6,7,8],用列表解析可以这样写:

a=[[1,2],[3,4,5],[6,7],[8]]
[x  for i in a for x in i] 
out>>[1,2,3,4,5,6,7,8]

理解起来略有一点麻烦,for i in a,i为子列表,for x in i,x得到每个子列表中的值。这样的列表解析写法确实很难理解,所以有时候我们不要过分的使用复杂的列表解析。

例7,获取笛卡尔积

假设有三个配置列表

>>> a=['4k','8k','12k']                                                                                                                          
>>> b=['1','2,','3']                                                                                                                             
>>> c=['libaio','bio','directio'] 

我们想获取其笛卡尔积,列表解析的写法,得到:

[{
     'blocksize':x,'numjobs':y,'ioengine':z} for x in a for y in b for z in c] 

这样就得到一个包含所有参数项目的字典列表,避免了写若干个for循环

例8,获取所有可能的组合

假设有一个配置列表[‘a’,‘b’,‘c’],我们想获取所有的由a,b,c组成的字符串(可以重复使用,将顺序也考虑在内),列表解析需要配合itertools中的product函数:

from itertools import product
x=['a','b','c']
results = ["".join(i) for i in product(x, repeat=3)]
out>>['aaa', 'aab', 'aac', 'aba', 'abb', 'abc', 'aca', 'acb', 'acc', 'baa', 'bab', 'bac', 'bba', 'bbb', 'bbc', 'bca', 'bcb', 'bc                                            
c', 'caa', 'cab', 'cac', 'cba', 'cbb', 'cbc', 'cca', 'ccb', 'ccc']

例9,矩阵转置
考虑一个矩阵,matrix=[[1, 2, 3, 4], [2, 4, 6, 8], [3, 6, 9, 12]],现在要获得他的转置矩阵,用列表解析仍然是一行:

transposed = [list(row) for row in zip(*matrix)]

matrix使用zip解开(完成转置),列表解析负责将结果生成原来的列表嵌套列表的模式

这个case也可以不用列表解析:

transposed = list(map(list, zip(*matrix)))

使用map函数也是可以的(顺便提一下)

生成器表达式(Generator expressions)

不创建列表,只是返回一个生成器。这个生成器在每次计算出一个条目后,才把这个条目产生出来。所以在处理大量数据时更有优势。

不创建列表,只是返回一个生成器。这个生成器在每次计算出一个条目后,才把这个条目产生出来。所以在处理大量数据时更有优势。

语法:

(expression for iter_var in iterable1)

(expression for iter_var2 in iterable2 …
for iter_varN in iterableN)

(expression for iter_var in iterable1
if condition)

执行:

迭代iterable中所有的元素,每一次迭代都把iterable中的内容放到iter_var对象中,然后把这个对象应用到表达式expression中,生成一个生成器。

Python 列表解析与生成器表达式_第2张图片

你可能感兴趣的:(python,开发语言,生物信息学)