3.1 索引列表 VS 字典
我们已经看到,文本在 Python 中被视为一个词列表。链表的一个重要的属性是我们可以通过给出其索引来“看”特定项目,例如text1[100]
。请注意我们如何指定一个数字,然后取回一个词。我们可以把链表看作一种简单的表格,如3.1所示。
图 3.1:列表查找:一个整数索引帮助我们访问 Python 列表的内容。
对比这种情况与频率分布(3),在那里我们指定一个词然后取回一个数字,如fdist['monstrous']
,它告诉我们一个给定的词在文本中出现的次数。用词查询对任何使用过字典的人都很熟悉。3.2展示一些更多的例子。
图 3.2:字典查询:我们使用一个关键字,如某人的名字、一个域名或一个英文单词,访问一个字典的条目;字典的其他名字有映射、哈希表、哈希和关联数组。
在电话簿中,我们用名字查找一个条目得到一个数字。当我们在浏览器中输入一个域名,计算机查找它得到一个 IP 地址。一个词频表允许我们查一个词找出它在一个文本集合中的频率。在所有这些情况中,我们都是从名称映射到数字,而不是其他如列表那样的方式。总之,我们希望能够在任意类型的信息之间映射。3.1列出了各种语言学对象以及它们的映射。
表 3.1:
语言学对象从键到值的映射
>>> pos = {}
>>> pos
{}
>>> pos['colorless'] = 'ADJ' ![[1]](/projects/nlp-py-2e-zh/Images/7a979f968bd33428b02cde62eaf2b615.jpg)
>>> pos
{'colorless': 'ADJ'}
>>> pos['ideas'] = 'N'
>>> pos['sleep'] = 'V'
>>> pos['furiously'] = 'ADV'
>>> pos ![[2]](/projects/nlp-py-2e-zh/Images/6ac827d2d00b6ebf8bbc704f430af896.jpg)
{'furiously': 'ADV', 'ideas': 'N', 'colorless': 'ADJ', 'sleep': 'V'}
所以,例如,说的是 colorless 的词性是形容词,或者更具体地说:在字典pos
中,键'colorless'
被分配了值'ADJ'
。当我们检查pos
的值时,我们看到一个键-值对的集合。一旦我们以这样的方式填充了字典,就可以使用键来检索值:
>>> pos['ideas']
'N'
>>> pos['colorless']
'ADJ'
当然,我们可能会无意中使用一个尚未分配值的键。
>>> pos['green']
Traceback (most recent call last):
File "<stdin>", line 1, in ?
KeyError: 'green'
这就提出了一个重要的问题。与列表和字符串不同,我们可以用len()
算出哪些整数是合法索引,我们如何算出一个字典的合法键?如果字典不是太大,我们可以简单地通过查看变量pos
检查它的内容。正如在前面(行)所看到,这为我们提供了键-值对。请注意它们的顺序与最初放入它们的顺序不同;这是因为字典不是序列而是映射(参见3.2),键没有固定地排序。
换种方式,要找到键,我们可以将字典转换成一个列表——要么在期望列表的上下文中使用字典,如作为sorted()
的参数,要么在for
循环中。
>>> list(pos) ![[1]](/projects/nlp-py-2e-zh/Images/7a979f968bd33428b02cde62eaf2b615.jpg)
['ideas', 'furiously', 'colorless', 'sleep']
>>> sorted(pos) ![[2]](/projects/nlp-py-2e-zh/Images/6ac827d2d00b6ebf8bbc704f430af896.jpg)
['colorless', 'furiously', 'ideas', 'sleep']
>>> [w for w in pos if w.endswith('s')] ![[3]](/projects/nlp-py-2e-zh/Images/934b688727805b37f2404f7497c52027.jpg)
['colorless', 'ideas']
注意
当你输入list(pos)
时,你看到的可能会与这里显示的顺序不同。如果你想看到有序的键,只需要对它们进行排序。
与使用一个for
循环遍历字典中的所有键一样,我们可以使用for
循环输出列表:
>>> for word in sorted(pos):
... print(word + ":", pos[word])
...
colorless: ADJ
furiously: ADV
sleep: V
ideas: N
最后,字典的方法keys()
、values()
和items()
允许我们以单独的列表访问键、值以及键-值对。我们甚至可以排序元组,按它们的第一个元素排序(如果第一个元素相同,就使用它们的第二个元素)。
>>> list(pos.keys())
['colorless', 'furiously', 'sleep', 'ideas']
>>> list(pos.values())
['ADJ', 'ADV', 'V', 'N']
>>> list(pos.items())
[('colorless', 'ADJ'), ('furiously', 'ADV'), ('sleep', 'V'), ('ideas', 'N')]
>>> for key, val in sorted(pos.items()): ![[1]](/projects/nlp-py-2e-zh/Images/7a979f968bd33428b02cde62eaf2b615.jpg)
... print(key + ":", val)
...
colorless: ADJ
furiously: ADV
ideas: N
sleep: V
我们要确保当我们在字典中查找某词时,一个键只得到一个值。现在假设我们试图用字典来存储可同时作为动词和名词的词 sleep:
>>> pos['sleep'] = 'V'
>>> pos['sleep']
'V'
>>> pos['sleep'] = 'N'
>>> pos['sleep']
'N'
最初,pos['sleep']
给的值是'V'
。但是,它立即被一个新值'N'
覆盖。换句话说,字典中只能有'sleep'
的一个条目。然而,有一个方法可以在该项目中存储多个值:我们使用一个列表值,例如pos['sleep'] = ['N', 'V']
。事实上,这就是我们在4中看到的 CMU 发音字典,它为一个词存储多个发音。