Chinaunix首页 | 论坛 | 博客
  • 博客访问: 377665
  • 博文数量: 97
  • 博客积分: 2846
  • 博客等级: 少校
  • 技术积分: 1000
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-19 20:00
文章分类

全部博文(97)

文章存档

2017年(1)

2013年(2)

2012年(6)

2011年(17)

2010年(12)

2009年(41)

2007年(18)

我的朋友

分类: Python/Ruby

2012-03-13 09:35:21

4.15  字典的一键多值

感谢:Credit: Michael Chermside

任务

需要一个字典,能够将每个键映射到多个值上。

解决方案

正常情况下,字典是一对一映射的,但要实现一对多映射也不难,换句话说,即一个键对应多个值。你有两个可选方案,但具体要看你怎么看待键的多个对应值的重复。下面这种方法,使用list作为dict的值,允许重复:

  1. d1 = {  }  
  2. d1.setdefault(key, [  ]).append(value) 

另一种方案,使用子字典作为dict的值,自然而然地消灭了值重复的可能:

  1. d2 = {  }  
  2. d2.setdefault(key, {  })[value] = 1 

在Python 2.4中,这种无重复值的方法可等价地被修改为:

  1. d3 = {  }  
  2. d3.setdefault(key, set( )).add(value) 

讨论

正常的字典简单地将一个键映射到一个值上。本节则展示了三个简单有效的方法来实现一个键对应多个值的功能,即将字典的值设为列表或字典,若在Python 2.4中,还有可能是集合。基于列表的方法的语义和其他两者差别不大,最重大的差别是它们对待值重复的态度。每种方式都依赖字典的setdefault方法(4.10节有相关内容)来初始化字典的一个键所对应的条目,并在需要的时候返回上述条目。

除了给键增加对应值之外,还要做更多的事情。对于使用列表并允许重复的第一个方式,下面代码可取得键对应的值列表:

  1. list_of_values = d1[key] 

如果不介意当键的所有值都被移除后,仍留下一个空列表作为d1的值,可以用下面方法删除键的对应值:

  1. d1[key].remove(value) 

虽然有空列表,但要想检查一个键是否至少有一个值还是很容易的,使用一个总是返回列表(也可能是空列表)的函数就行了:

  1. def get_values_if_any(d, key):  
  2.       return d.get(key, [  ]) 

比如,为了检查"freep"是否是字典d1的键"somekey"的对应值之一,可以这样编写代码:if 'freep' in get_values_if_any(d1, 'somekey')。

使用子字典且没有值重复的第二种方式的用法非常类似。为了获得键的对应值列表,具体做法是:

  1. listlist_of_values = list(d2[key]) 

为了移除某键的一个值,可以像下面这样做,当然,当键的值都被删除之后,字典d2中仍会留下一个空字典:

  1. del d2[key][value] 

第三种方式,只适用于Python 2.4以上并使用了集合的方式,它的移除键值的操作如下:

  1. d3[key].remove(value) 

第二和第三种方式(无重复)的get_value_if_any函数:

  1. def get_values_if_any(d, key):  
  2.       return list(d.get(key, ( ))) 

本节讨论了如何实现一个很基本的功能,但并没有提到如何以一种系统化的方式来应用它,你也许会考虑将这些代码封装成一个类。要达到这个目的,必须得通盘考虑你的设计。你能否接受某个值和某个键的对应关系出现多次?(用数学的语言可表述为,对于每个键而言,条目究竟是包还是集合?)如果是的话,则remove方法究竟是将总的对应次数减一,还是完全地删掉那些对应关系?这只是你面临各种各样决定的一个开始,不过,要想做出正确选择,必须基于应用的实际需求来考虑。

阅读(6013) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~