Python进阶篇之字典操作总结


Posted in Python onNovember 16, 2016

一、与字典值有关的计算

问题

想对字典的值进行相关计算,例如找出字典里对应值最大(最小)的项。

解决方案一:

假设要从字典 {'a':3, 'b':2, 'c':6} 中找出值最小的项,可以这样做:

>>> d = {'a':3, 'b':2, 'c':6}
>>> min(zip(d.values(), d.keys()))
(2, 'b')

值得注意的是  d.values() 获取字典的全部值,d.keys() 获取字典的全部键,而且两个序列的顺序依然保持一一对应的关系。因此 zip(d.values() , d.keys()) 实质上生成的是一个 (value, key) 的序列。min 函数通过比较序列中的元组 (value, key) 找出其最小值。

解决方案二:

除了使用 zip(d.values() ,  d.keys()) 外,还可以使用 dict.items() 方法和生成器推导式来生成 (value, key) 序列,从而传递给 min 函数进行比较:

>>> d = {'a':3, 'b':2, 'c':6}
>>> min((v ,k) for (k, v) in d.items())
(2, 'b')

这里 min 函数的参数 (v ,k) for (k, v) in d.items() 其实是一个生成器推导式(和列表推导式一样,只是把列表推导式的 [] 改为 () ,而且其返回的一个生成器而非列表),由于生成器推导式做为 min 函数的参数,所以可以省略掉两边的括号(不做为参数时写法应该是 ((v ,k) for (k, v) in d.items()) )

二、字典推导式

问题

想把一个元组列表转换成一个字典,例如把 [('a', 1), ('b', 2), ('c', 3)] 转化为 {'a': 1, 'b': 2, 'c': 3}

解决方案

类似于列表推导式,字典推导式可以方便地从其他数据结构构造字典,例如:

>>> l = [('a', 1), ('b', 2), ('c', 3)]
>>> {k: v for k, v in l}
{'c': 3, 'b': 2, 'a': 1}

字典推导式的规则和列表推导式一样,只是把 [] 换成 {}

三、寻找字典的交集

问题

假设有两个字典:

d1 = {'a':1, 'b':2, 'c':3, 'd':4}
d2 = {'b':2, 'c':3, 'd':3, 'e':5}

要找出这两个字典中具有公共键的项,即要得到结果 {'b':2, 'c':3}

解决方案

我们知道一般通过 d.items() 方法来遍历字典,d.items() 方法返回的对象是一个类集合对象,支持集合的基本运算,如取交集、并集等。

>>> dict(d1.items() & d2.items()) # 取交集
{'b': 2, 'c': 3}

此外,d.keys() 返回字典的键,也是一个类集合对象,如果我们只想找出两个字典中键相同的项,可以这样:

>>> { k:d1[k] for k in d1.keys() & d2.keys() }
{'b': 2, 'd': 4, 'c': 3}

这里如果相同的键对应不同的值则去第一个字典中的值。推广开来,如果想排除掉字典中的某些键,可以这样:

>>> { k:d1[k] for k in d1.keys() - {'c', 'd'} } # - 号的含义是集合的差集操作
{'b': 2, 'a': 1}

但有一点需要注意的是,d.values() 返回字典的值,由于字典对应的值不一定唯一,所以 d.values() 一般无法构成一个集合,因此也就不支持一般的集合操作。

四、多个字典连接成一个字典

问题

有多个字典,例如:

d1 = {'a':1, 'b':2, 'c':3}
d2 = {'c':4, 'd':5, 'e':6}

想将这多个字典连接为一个字典,或一次性对多个字典进行迭代操作。

解决方案

使用 collections.ChainMap 

>>> from collections import ChainMap

>>> chain_dict = ChainMap(d1, d2)
>>> for k, v in chain_dict.items():
    print(k, v)
a 1
e 6
d 5
c 3
b 2

ChainMap 将传入的多个字典连接为一个字典,并返回一个 ChainMap 对象,这个对象的行为就像一个单一的字典,我们可以对其进行取值或者迭代等操作。注意到这里键 c 对应的值为 3,如果传入 ChainMap 的字典含有相同的键,则对应的值为先传入的字典中的值。

此外,如果你只想单纯地迭代字典的键值对,可以结合使用 items() itertools.chain() 方法:

>>> from itertools import chain
>>> for k, v in chain(d1.items(), d2.items()):
  print(k, v)

a 1
c 3
b 2
e 6
c 4
d 5

这里相同的键会被分别迭代出来。

五、保持字典有序

问题

想让字典中元素的迭代顺序和其加入字典的顺序保持一致

解决方案

通常来说,使用 d.items() 或者 d.keys()d.values() 方法迭代出来的元素顺序是无法预料的。例如对字典 d = {'a':1, 'b':2, 'c':3} 迭代:

>>> d = dict()
>>> d['a'] = 1
>>> d['b'] = 2
>>> d['c'] = 3
>>> for k, v in d.items():
  print(k, v)

a 1
c 3
b 2

每一次运行结果都可能不同。如果想让元素迭代的顺序和创建字典时元素的顺序一致,就要使用 collections.OrderedDict 代替普通的 dict :

>>> from collections import OrderedDict
>>> ordered_d = OrderedDict()
>>> ordered_d['a'] = 1
>>> ordered_d['b'] = 2
>>> ordered_d['c'] = 3
>>> for k, v in ordered_d.items():
  print(k, v)

a 1
b 2
c 3

OrderedDict 实际通过维护一个双向链表来记录元素添加的顺序,因此其耗费的内存大约为普通字典的两倍。所以在实际使用中需综合考虑各种因素来决定是否使用 OrderedDict 。

六、使字典的键映射多个值

问题

通常情况下字典的键只对应一个值。现在想让一个键对应多个值。

解决方案

为了使一个键对应多个值,首先需要把多个值放到一个容器中(例如列表或者集合等)。例如有这样一个列表: [('a', 1), ('a', 2), ('b', 3), ('b', 4), ('c', 5)] ,我们要将其转换成一个字典,保持元素的键值对应关系,通常我们会写这样的代码:

>>> from pprint import pprint
>>> l = [('a', 1), ('a', 2), ('b', 3), ('b', 4), ('c', 5)]
>>> d = {}
>>> for k, v in l:
  if k in d:
    d[k].append(v)
  else:
    d[k] = [v]

>>> pprint(d)
{'a': [1, 2], 'b': [3, 4], 'c': [5]}

但是 if else 语句让代码显得有点冗余和不易读,Python 的 defaultdict 改善上述代码。

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> for k, v in l:
  d[k].append(v)

>>> pprint(d)
defaultdict(<class 'list'>, {'c': [5], 'b': [3, 4], 'a': [1, 2]})

if else 的判语句没有了。

defaultdict 是 dict 的一个子类。对 dict 来说,如果 key 不存在,则 dict[key] 取值操作会抛出 KeyError 异常,但是 defaultdict 则会返回一个传入 defaultdict 构造器的类的实例(例如一个列表)或者自定义的缺失值。因此在上例中,对于 d[k].append(v) ,当 k 不存在时,则会先执行 d[k] = [] 并返回这个空列表,继而将 v 加入到列表中。

传入 defualtdict 构造器的值不一定要是一个类,也可以是一个可调用的函数,当相应的键不在 defualtdict 中时,其默认的值就为这个函数的返回值,例如:

>>> from collections import defaultdict
>>> def zero_default():
  return 0

>>> d = defaultdict(zero_default)
>>> d['a'] = 1
>>> d['a']
1

>>> d['b']
0

>>> d.keys()
dict_keys(['b', 'a'])
>>>

利用这样一个特性,我们可以构造无限深度的字典结构:

>>> from collections import defaultdict
>>> import json
>>> tree = lambda: defaultdict(tree)
>>> d = tree()
>>> d['a']['b'] = 1
>>> print(json.dumps(d)) # 为了显示的格式更好看
{"a": {"b": 1}}

这里当执行 d['a'] 时,由于相应的键不存在,故返回一个 defaultdict(tree) ,当再执行 d['a']['b'] = 1 时,将键 b 对应的值设为 1 。

总结

以上就是这篇文中的全部内容,希望本文的内容对大家学习或者使用python能有一定的帮助,如果有疑问大家可以留言交流。

Python 相关文章推荐
使用Python判断IP地址合法性的方法实例
Mar 13 Python
Python中使用第三方库xlrd来读取Excel示例
Apr 05 Python
Python 性能优化技巧总结
Nov 01 Python
python利用不到一百行代码实现一个小siri
Mar 02 Python
python基础之包的导入和__init__.py的介绍
Jan 08 Python
Python enumerate索引迭代代码解析
Jan 19 Python
Python面向对象类继承和组合实例分析
May 28 Python
python中for用来遍历range函数的方法
Jun 08 Python
python统计多维数组的行数和列数实例
Jun 23 Python
Selenium的使用详解
Oct 19 Python
tensorflow通过模型文件,使用tensorboard查看其模型图Graph方式
Jan 23 Python
python b站视频下载的五种版本
May 27 Python
Python极简代码实现杨辉三角示例代码
Nov 15 #Python
Python实现将不规范的英文名字首字母大写
Nov 15 #Python
利用Python开发实现简单的记事本
Nov 15 #Python
Python解析excel文件存入sqlite数据库的方法
Nov 15 #Python
听歌识曲--用python实现一个音乐检索器的功能
Nov 15 #Python
Python字典简介以及用法详解
Nov 15 #Python
python xml解析实例详解
Nov 14 #Python
You might like
在windows平台上构建自己的PHP实现方法(仅适用于php5.2)
2013/07/05 PHP
十幅图告诉你什么是PHP引用
2015/02/22 PHP
typecho插件编写教程(五):核心代码
2015/05/28 PHP
PHP实现适用于自定义的验证码类
2016/06/15 PHP
Laravel的throttle中间件失效问题解决方法
2016/10/09 PHP
Yii2 hasOne(), hasMany() 实现三表关联的方法(两种)
2017/02/15 PHP
js截取函数(indexOf,join等)
2010/09/01 Javascript
JavaScript合并两个数组并去除重复项的方法
2015/06/13 Javascript
13个PHP函数超实用
2015/10/21 Javascript
JavaScript基础之AJAX简单的小demo
2017/01/29 Javascript
详解微信小程序中的页面代码中的模板的封装
2017/10/12 Javascript
js实现无刷新监听URL的变化示例代码详解
2020/06/03 Javascript
详解阿里Node.js技术文档之process模块学习指南
2021/01/04 Javascript
python将xml xsl文件生成html文件存储示例讲解
2013/12/03 Python
从零学python系列之教你如何根据图片生成字符画
2014/05/23 Python
python根据出生日期获得年龄的方法
2015/03/31 Python
Python进行数据提取的方法总结
2016/08/22 Python
Python中防止sql注入的方法详解
2017/02/25 Python
Python subprocess模块详细解读
2018/01/29 Python
Win7 64位下python3.6.5安装配置图文教程
2020/10/27 Python
python通过伪装头部数据抵抗反爬虫的实例
2018/05/07 Python
对dataframe进行列相加,行相加的实例
2018/06/08 Python
Python3中bytes类型转换为str类型
2018/09/27 Python
利用Python对文件夹下图片数据进行批量改名的代码实例
2019/02/21 Python
CSS3 实现侧边栏展开收起动画
2014/12/22 HTML / CSS
英国休闲奢华的缩影:Crew Clothing
2019/05/05 全球购物
金鑫耀Java笔试题
2014/09/06 面试题
临床医师专业个人自我评价
2014/01/08 职场文书
护士毕业生自荐信
2014/02/07 职场文书
2014离婚协议书范文(3篇)
2014/11/29 职场文书
高三物理教学反思
2016/02/20 职场文书
如何使用vue3打造一个物料库
2021/05/08 Vue.js
springboot临时文件存储目录配置方式
2021/07/01 Java/Android
sass 常用备忘案例详解
2021/09/15 HTML / CSS
Python实现科学占卜 让视频自动打码
2022/04/09 Python
ant design vue的form表单取值方法
2022/06/01 Vue.js