目录 | 上一节 (2.5 collections模块) | 下一节 (2.7 对象模型)

2.6 列表推导式

一个常见的任务是处理列表中的项(译注:元素)。本节介绍列表推导式,完成此任务的强大工具。

创建新列表

列表推导式通过将操作应用于序列的每一个元素来创建新列表。

>>> 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']
>>>

列表推导式的一般语法是:[ <expression> for <variable_name> in <sequence> ]

过滤

也可以在列表推导式中对元素进行过滤。

>>> 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])

一般语法

[ <expression> for <variable_name> in <sequence> if <condition>]

上面语法的含义:

result = []
for variable_name in sequence:
if condition:
result.append(expression)

历史题外话

列表推导式来自于数学(集合构建符号)。

a = [ x * x for x in s if x > 0 ] # Python

a = { x^2 | x ∈ s, x > 0 }         # Math

这在其它几种语言中也实现了,虽然大部分的程序员可能已经想不起他们的数学课了。所以,可以将其视为很酷的列表快捷方式。

练习

首先运行 report.py 程序,以便能够在交互模式下中加载股票投资组合。

bash % python3 -i report.py

现在,在 Python 交互提示符下,输入语句以执行下述操作。这些操作对投资组合数据执行各类缩减,转换和查找。

练习 2.19:列表推导式

尝试一些简单的列表推导式来熟悉语法:

>>> 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]
>>>

请注意列表推导式是如何通过适当转换或过滤的数据创建一个新列表的。

练习 2.20:序列缩减

使用单个 Python 语句计算投资组合的总价。

>>> portfolio = read_portfolio('Data/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
>>>

有了这些知识,你现在就可以准备成立一家大数据创业公司了。

练习 2.21:数据查询

请尝试以下各种数据查询示例。

首选是创建一个列表,存储持有 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}]
>>>

练习 2.22:数据提取

展示如何构建元组 (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)]
>>>

如果将方括号([,])更改为花括号({, }),那么将得到集合推导式。这会得到独一无二的的或无重复的值。

例如,这将确定集合中的股票名称是独一无二的:

>>> names = { s['name'] for s in portfolio }
>>> names
{ 'AA', 'GE', 'IBM', 'MSFT', 'CAT' }
>>>

如果指定键值对(key:value),则可以构建一个字典。例如,构建一个将股票名称映射到持有的股票数量的字典:

>>> 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 中出现的名称(name):

>>> 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}
>>>

练习 2.23: 从 CSV 文件提取数据

在各类数据处理中,知道如何将列表,集合,字典推导式联合使用会非常有用。这里有一个示例,展示如何从 CSV 文件中提取所选择的列。

首先,从 CSV 文件读取一行标题信息:

>>> import csv
>>> f = open('Data/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 模块。

目录 | 上一节 (2.5 collections模块) | 下一节 (2.7 对象模型)

翻译:《实用的Python编程》02_06_List_comprehension的更多相关文章

  1. 翻译:《实用的Python编程》InstructorNotes

    实用的 Python 编程--讲师说明 作者:戴维·比兹利(David Beazley) 概述 对于如何使用我的课程"实用的 Python 编程"进行教学的问题,本文档提供一些通用 ...

  2. 翻译:《实用的Python编程》README

    欢迎光临 大约 25 年前,当我第一次学习 Python 时,发现 Python 竟然可以被高效地应用到各种混乱的工作项目上,我立即被震惊了.15 年前,我自己也将这种乐趣教授给别人.教学的结果就是本 ...

  3. 翻译:《实用的Python编程》05_02_Classes_encapsulation

    目录 | 上一节 (5.1 再谈字典) | 下一节 (6 生成器) 5.2 类和封装 创建类时,通常会尝试将类的内部细节进行封装.本节介绍 Python 编程中有关封装的习惯用法(包括私有变量和私有属 ...

  4. 翻译:《实用的Python编程》04_02_Inheritance

    目录 | 上一节 (4.1 类) | 下一节 (4.3 特殊方法) 4.2 继承 继承(inheritance)是编写可扩展程序程序的常用手段.本节对继承的思想(idea)进行探讨. 简介 继承用于特 ...

  5. 翻译:《实用的Python编程》01_02_Hello_world

    目录 | 上一节 (1.1 Python) | 下一节 (1.3 数字) 1.2 第一个程序 本节讨论有关如何创建一个程序.运行解释器和调试的基础知识. 运行 Python Python 程序始终在解 ...

  6. 翻译:《实用的Python编程》03_03_Error_checking

    目录 | 上一节 (3.2 深入函数) | 下一节 (3.4 模块) 3.3 错误检查 虽然前面已经介绍了异常,但本节补充一些有关错误检查和异常处理的其它细节. 程序是如何运行失败的 Python 不 ...

  7. 翻译:《实用的Python编程》03_04_Modules

    目录 | 上一节 (3.3 错误检查) | 下一节 (3.5 主模块) 3.4 模块 本节介绍模块的概念以及如何使用跨多个文件的函数. 模块和导入 任何一个 Python 源文件都是一个模块. # f ...

  8. 翻译:《实用的Python编程》03_05_Main_module

    目录 | 上一节 (3.4 模块) | 下一节 (3.6 设计讨论) 3.5 主模块 本节介绍主程序(主模块)的概念 主函数 在许多编程语言中,存在一个主函数或者主方法的概念. // c / c++ ...

  9. 翻译:《实用的Python编程》04_01_Class

    目录 | 上一节 (3.6 设计讨论) | 下一节 (4.2 继承) 4.1 类 本节介绍 class 语句以及创建新对象的方式. 面向对象编程(OOP) 面向对象编程是一种将代码组织成对象集合的编程 ...

随机推荐

  1. 怎样将Sublime Text 设置成中文版(完整教程)

    1.打开Sublime Text,使用快捷键Shift+Ctrl+P,弹出查找栏,如图: 2.在搜索框中输入关键字 install ,出现下拉选项,点击选择其中的:Package Control: I ...

  2. 2019 ccpc秦皇岛

    1006 (dfs) #include <bits/stdc++.h> using namespace std; const int inf = 0x3f3f3f3f; const dou ...

  3. Codeforces Round #316 (Div. 2) D. Tree Requests(dsu)

    题目链接 题意:对于m次询问 求解以vi为根节点 深度为hi的的字母能不能组合成回文串. 思路:暴力dsu找一边 简直就是神技! #include<bits/stdc++.h> #defi ...

  4. Codeforces Round #652 (Div. 2) D. TediousLee(dp)

    题目链接:https://codeforces.com/contest/1369/problem/D 题意 最初有一个结点,衍生规则如下: 如果结点 $u$ 没有子结点,添加 $1$ 个子结点 如果结 ...

  5. Codeforces Round #602 Div2 D1. Optimal Subsequences (Easy Version)

    题意:给你一个数组a,询问m次,每次返回长度为k的和最大的子序列(要求字典序最小)的pos位置上的数字. 题解:和最大的子序列很简单,排个序就行,但是题目要求字典序最小,那我们在刚开始的时候先记录每个 ...

  6. linux搭建网站

    CentOS 1.安装 yum -y install nginx *或者安装指定版本,版本网址:http://nginx.org/packages/centos/7/x86_64/RPMS/ rpm ...

  7. NLP论文阅读一:Paper阅读方法

    参考:https://pan.baidu.com/s/1MfcmXKopna3aLZHkD3iL3w 一.为什么要读论文? 基础技术:读论文中的related works可以帮助了解该领域的一些主要的 ...

  8. String的20个方法

    String的20个方法 面试题 1.new和不new的区别 String A="OK"; String B="OK";//会去常量池查找有没有"Ok ...

  9. HDU - 4462 Scaring the Birds

    It's harvest season now! Farmer John plants a lot of corn. There are many birds living around his co ...

  10. pikachu-反射性xss(get)

    首先打开漏洞网页,发现输入的长度好像被限制了, 我们便F12查看源代码,发现长度被限制成了20,而且还是前端验证的,我们可以直接修改为100 在我们的输入框中,输入 <script>ale ...