简介
一项常见的任务是处理列表中的元素。本节将介绍列表推导式,这是一种用于完成此项任务的强大工具。
一项常见的任务是处理列表中的元素。本节将介绍列表推导式,这是一种用于完成此项任务的强大工具。
列表推导式通过对序列中的每个元素应用一个操作来创建一个新列表。
>>> a = [1, 2, 3, 4, 5]
>>> b = [2*x for x in a ]
>>> b
[2, 4, 6, 8, 10]
>>>
另一个示例:
>>> names = ['Elwood', 'Jake']
>>> a = [name.lower() for name in names]
>>> a
['elwood', 'jake']
>>>
一般语法为:[ <表达式> for <变量名> in <序列> ]。
你还可以在列表推导式过程中进行过滤。
>>> a = [1, -5, 4, 2, -2, 10]
>>> b = [2*x for x in a if x > 0 ]
>>> b
[2, 8, 4, 20]
>>>
列表推导式非常有用。例如,你可以收集特定字典字段的值:
stocknames = [s['name'] for s in stocks]
你可以对序列执行类似数据库的查询。
a = [s for s in stocks if s['price'] > 100 and s['shares'] > 50 ]
你还可以将列表推导式与序列归约相结合:
cost = sum([s['shares']*s['price'] for s in stocks])
[ <表达式> for <变量名> in <序列> if <条件>]
它的含义如下:
result = []
for 变量名 in 序列:
if 条件:
result.append(表达式)
列表推导式源自数学(集合构造记号)。
a = [ x * x for x in s if x > 0 ] ## Python
a = { x^2 | x ∈ s, x > 0 } ## 数学
它在其他几种语言中也有实现。不过,大多数程序员可能不会联想到他们的数学课。所以,将其视为一种很棒的列表快捷方式也无妨。
尝试一些简单的列表推导式,只是为了熟悉其语法。
>>> nums = [1,2,3,4]
>>> squares = [ x * x for x in nums ]
>>> squares
[1, 4, 9, 16]
>>> twice = [ 2 * x for x in nums if x > 2 ]
>>> twice
[6, 8]
>>>
注意列表推导式是如何通过对数据进行适当的转换或过滤来创建一个新列表的。
使用一条 Python 语句计算投资组合的总成本。
>>> portfolio = read_portfolio('portfolio.csv')
>>> cost = sum([ s['shares'] * s['price'] for s in portfolio ])
>>> cost
44671.15
>>>
完成上述操作后,展示如何使用一条语句计算投资组合的当前价值。
>>> value = sum([ s['shares'] * prices[s['name']] for s in portfolio ])
>>> value
28686.1
>>>
上述两个操作都是映射归约的示例。列表推导式在列表上映射一个操作。
>>> [ s['shares'] * s['price'] for s in portfolio ]
[3220.0000000000005, 4555.0, 12516.0, 10246.0, 3835.1499999999996, 3254.9999999999995, 7044.0]
>>>
然后 sum() 函数对结果进行归约:
>>> sum(_)
44671.15
>>>
有了这些知识,你现在就可以准备去创办一家大数据初创公司了。
尝试以下各种数据查询示例。
首先,列出所有持有股份超过 100 股的投资组合。
>>> more100 = [ s for s in portfolio if s['shares'] > 100 ]
>>> more100
[{'price': 83.44, 'name': 'CAT','shares': 150}, {'price': 51.23, 'name': 'MSFT','shares': 200}]
>>>
所有持有微软(MSFT)和 IBM 股票的投资组合。
>>> msftibm = [ s for s in portfolio if s['name'] in {'MSFT', 'IBM'} ]
>>> msftibm
[{'price': 91.1, 'name': 'IBM','shares': 50}, {'price': 51.23, 'name': 'MSFT','shares': 200},
{'price': 65.1, 'name': 'MSFT','shares': 50}, {'price': 70.44, 'name': 'IBM','shares': 100}]
>>>
列出所有成本超过 10000 美元的投资组合。
>>> cost10k = [ s for s in portfolio if s['shares'] * s['price'] > 10000 ]
>>> cost10k
[{'price': 83.44, 'name': 'CAT','shares': 150}, {'price': 51.23, 'name': 'MSFT','shares': 200}]
>>>
展示如何构建一个元组列表 (name, shares),其中 name 和 shares 取自 portfolio。
>>> name_shares =[ (s['name'], s['shares']) for s in portfolio ]
>>> name_shares
[('AA', 100), ('IBM', 50), ('CAT', 150), ('MSFT', 200), ('GE', 95), ('MSFT', 50), ('IBM', 100)]
>>>
如果你将方括号 ([, ]) 改为花括号 ({, }),你将得到所谓的集合推导式。这会给你唯一或不同的值。
例如,这可以确定 portfolio 中出现的唯一股票名称集合:
>>> names = { s['name'] for s in portfolio }
>>> names
{ 'AA', 'GE', 'IBM', 'MSFT', 'CAT' }
>>>
如果你指定 键:值 对,就可以构建一个字典。例如,创建一个将股票名称映射到所持股票总数的字典。
>>> holdings = { name: 0 for name in names }
>>> holdings
{'AA': 0, 'GE': 0, 'IBM': 0, 'MSFT': 0, 'CAT': 0}
>>>
后一个特性称为 字典推导式。让我们列表如下:
>>> for s in portfolio:
holdings[s['name']] += s['shares']
>>> holdings
{ 'AA': 100, 'GE': 95, 'IBM': 150, 'MSFT':250, 'CAT': 150 }
>>>
尝试这个示例,它将 prices 字典过滤为只包含 portfolio 中出现的那些名称:
>>> portfolio_prices = { name: prices[name] for name in names }
>>> portfolio_prices
{'AA': 9.22, 'GE': 13.48, 'IBM': 106.28, 'MSFT': 20.89, 'CAT': 35.46}
>>>
了解如何使用列表、集合和字典推导式的各种组合在各种形式的数据处理中可能会很有用。下面是一个示例,展示了如何从 CSV 文件中提取选定的列。
首先,从 CSV 文件中读取一行标题信息:
>>> import csv
>>> f = open('portfoliodate.csv')
>>> rows = csv.reader(f)
>>> headers = next(rows)
>>> headers
['name', 'date', 'time','shares', 'price']
>>>
接下来,定义一个变量,列出你实际关心的列:
>>> select = ['name','shares', 'price']
>>>
现在,在源 CSV 文件中找到上述列的索引:
>>> indices = [ headers.index(colname) for colname in select ]
>>> indices
[0, 3, 4]
>>>
最后,读取一行数据,并使用字典推导式将其转换为字典:
>>> row = next(rows)
>>> record = { colname: row[index] for colname, index in zip(select, indices) } ## dict-comprehension
>>> record
{'price': '32.20', 'name': 'AA','shares': '100'}
>>>
如果你对刚才发生的事情感觉很熟悉了,那就读取文件的其余部分:
>>> portfolio = [ { colname: row[index] for colname, index in zip(select, indices) } for row in rows ]
>>> portfolio
[{'price': '91.10', 'name': 'IBM','shares': '50'}, {'price': '83.44', 'name': 'CAT','shares': '150'},
{'price': '51.23', 'name': 'MSFT','shares': '200'}, {'price': '40.37', 'name': 'GE','shares': '95'},
{'price': '65.10', 'name': 'MSFT','shares': '50'}, {'price': '70.44', 'name': 'IBM','shares': '100'}]
>>>
哇哦,你刚刚把 read_portfolio() 函数的大部分内容简化为了一条语句。
在 Python 中,列表推导式通常作为一种高效的方式来转换、过滤或收集数据。由于其语法的原因,你不要过度使用——尽量让每个列表推导式都保持简单。把事情分解成多个步骤是可以的。例如,你可能不想把最后一个例子突然扔给毫无防备的同事。
话虽如此,知道如何快速处理数据是一项非常有用的技能。在很多情况下,你可能需要解决某种一次性的问题,涉及数据的导入、导出、提取等等。成为列表推导式的大师级人物可以大幅减少设计解决方案所花费的时间。另外,别忘了 collections 模块。
恭喜你!你已经完成了列表推导式实验。你可以在 LabEx 中练习更多实验来提升你的技能。