python字典反转_4.14 反转字典

4.14  反转字典

感谢:Joel Lawhead、Ian Bollinger、Raymond Hettinger

任务

给定一个字典,此字典将不同的键映射到不同的值。而你想创建一个反转的字典,将各个值反映射到键。

解决方案

可以创建一个函数,此函数传递一个列表推导作为dict的参数以创建需要的字典。def invert_dict(d):

return dict([ (v, k) for k, v in d.iteritems( ) ])

对于比较大的字典,用Python标准库itertools模块提供的izip会更快一些:from itertools import izip

def invert_dict_fast(d):

return dict(izip(d.itervalues( ), d.iterkeys( )))

讨论

如果字典d中的值不是***的,那么d无法被真正地反转,也就是不存在这样的字典,对于任意给定的键k,满足id[d[k]]==k。不过,本节展示的函数在这种情况下仍然能够创建一个"伪反转"字典pd,对于任何属于字典d地值v,d[pd[v]]==v。如果给你原始的字典d,以及用本节函数获得的字典x,可以很容易地检查x是d的反转字典还是伪反转字典:当且仅当len(x)==len(d)时,x才是d的真正的反转字典。这是因为,如果两个不同的键对应相同的值,对于解决方案给出的两个函数来说,两个键中的一个一定会消失,因而生成的伪反转字典的长度也会比原字典的长度短。在任何情况下,只有当d中的值是可哈希(hashable,意味着可以用它们做字典的键)的,前面展示的函数才能正常工作,否则,函数会抛出一个TypeError异常。

当我们编写Python程序时,我们通常会"无视小的优化",正如Donald Knuth在30年前所说的"比起速度,我们更珍视清晰和正确性。"不过,了解更多让程序变快的知识也没有害处:当我们为了简单和清晰而采用某种方法编写程序时,我们***深入地考虑一下我们的决定,不要懵懵懂懂。

在这里,解决方案中的invert_dict函数可能会被认为更清晰,因为它清楚地表达了它在做的事。该函数取得了由iteritems方法生成的成对的键及其对应值k和v,将它们包裹成(value, key)的顺序,并把***生成的序列作为参数赋给dict,这样dict就构建出了一个值成为键,而原先的键变成了对应值的新字典-正是我们需要的反转字典。

而解决方案中invert_dict_fast函数其实也没有那么复杂,它的操作更加抽象,它首先将所有的键和值分别转为两个独立的迭代器,再通过调用Python标准库itertools模块提供的izip将两个迭代器转化为一个迭代器,其中每个元素都是像(value, key)一样的一对值。如果你能够习惯于这种抽象层次,你将体会到更高层次的简洁和清晰。

由于这种高度的抽象性,以及不具化(materialize)整个列表(而是通过生成器和迭代器一次生成一项)的特性,invert_dict_fast能够比invert_dict快很多。比如,在我的计算机上,反转10 000个条目的字典,invert_dict耗时63ms,而invert_dict_fast则仅用时20ms。速度提升了3倍,颇为可观。当你处理大规模数据时,由于代码的高度抽象性而带来的性能提升将会变得更加明显。特别是当你使用itertools来替换循环和列表推导时,执行速度同样也能获得极大提升,因为你无须在内存中具化一些超大的列表。当你习惯了更高的抽象层次,性能的提升只是一个额外收益,除此之外,你在观念和创造性上也会有所进步。

更多资料

Library Reference和Python in a Nutshell中的映射类型和itertools的文档;第19章。

【责任编辑:云霞 TEL:(010)68476606】

点赞 0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值