在Python中使用zip或dict函数将列表转换为字典
经过多次尝试,我终于写出了下面的代码,可以从一个特定的CSV文件中索引特定的列和行。现在我想把下面的代码转换成一个字典。我看过关于字典和zip的文档,但还是不太明白……
这个CSV文件包含500条记录,列A到L对应下面的标题:
名字, 姓氏, 公司, 地址, 城市, 县, 州, 邮政编码, 电话1, 电话2, 电子邮件, 网站
import csv
f= open('us-500.csv', 'rU')
reader = csv.reader(f) # use list or next
rows = list(reader)
for row in rows[0:20]:
print "".join(row[8])
5 个回答
你可以使用 dict
推导式。
list1 = range(10)
list2 = range(20)
a = {k: v for k, v in zip(list1, list2)}
print a
也可以使用 dict()
方法。
b = dict(zip(list1, list2))
这两种方式的输出结果是一样的:
{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}
{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}
如果你能把数据整理成两个列表(并且这两个列表的顺序是你想要的),那么你就可以准备把它们转换成字典了。
>>> list_1 = ['pie','farts','boo']
>>>
>>> list_2 = ['apple','stanky','scary']
>>>
>>> dict(zip(list_1,list_2))
{'boo': 'scary', 'farts': 'stanky', 'pie': 'apple'}
>>>
>>> dict(zip(list_2,list_1))
{'apple': 'pie', 'stanky': 'farts', 'scary': 'boo'}
>>>
zip命令挺有意思的,因为它可以把两个列表合并成一个新的列表,这个新列表里面包含了小列表。
>>> list(zip(list_1,list_2))
[('pie', 'apple'), ('farts', 'stanky'), ('boo', 'scary')]
然后你只需要把这个新列表转换成字典就可以了。
>>> dict(zip(list_1,list_2))
{'boo': 'scary', 'farts': 'stanky', 'pie': 'apple'}
根据你的评论,听起来你想要的是这样的东西:
- 一系列的行。
- 一个或多个“索引”多字典,用来把某一列的值和拥有这个值的行号对应起来。
所谓的“多字典”,就是一种字典,它把键映射到某种集合,比如集合或列表。你可以很简单地通过使用 defaultdict
来构建一个。
你可以使用 enumerate
函数来获取每一行的行号和它的值列表。
那么,让我们在你的数据上建立几个索引:
import collections
import csv
f= open('us-500.csv', 'rU')
reader = csv.reader(f) # use list or next
rows = list(reader)
phone1_index = collections.defaultdict(set)
phone2_index = collections.defaultdict(set)
for i, row in enumerate(rows):
phone1_index[row[8]].add(i)
phone2_index[row[9]].add(i)
(注意,这其实和典型数据库中的索引不完全一样——它可以很好地找到所有 where phone1 == ?
的行,但对 where phone1 < ?
就没什么帮助了。)
不过,实际上没有必要一定要考虑索引。如果你直接把行存储在字典里,其实并不会浪费空间;在Python中,你可以有两个指向同一个对象的引用,而不需要复制所有数据。
有一个小问题,就是行是列表,而列表是可变的,因此不能存储在集合中。但你可能并不想让它们是可变的,它们只是恰好是这样,所以你可以用元组来代替:
f= open('us-500.csv', 'rU')
reader = csv.reader(f) # use list or next
phone1_map = collections.defaultdict(set)
phone2_map = collections.defaultdict(set)
for row in reader:
row = tuple(row)
phone1_map[row[8]].add(row)
phone2_map[row[9]].add(row)
顺便说一下,这看起来是 namedtuple
的一个好用例:
header = 'first_name, last_name, company, address, city, county, state, zip, phone1, phone2, email, web'
Row = collections.namedtuple('Row', header.split(', '))
f= open('us-500.csv', 'rU')
reader = csv.reader(f) # use list or next
phone1_map = collections.defaultdict(set)
phone2_map = collections.defaultdict(set)
for row in reader:
row = Row(row)
phone1_map[row.phone1].add(row)
phone2_map[row.phone2].add(row)
所以,现在如果你想找到所有 phone1
或 phone2
是 1.555.555.1212
的人的姓氏:
matches = phone1_map['1.555.555.1212'] | phone2_map['1.555.555.1212']
names = {match.name for match in matches}
我来猜猜你想要的是什么。
你有一个CSV文件,里面大概有10列。
你想要一个字典,这个字典的键是每一行的第8列的值,而对应的值是整行的数据(也就是所有列的一个列表)。
所以,你不想要list(reader)
那样的结果,因为它只会给你一堆行的列表,你想要的是这样的:
d = {row[8]: row for row in reader}
或者,如果你使用的是Python 2.5,并且没有字典推导式的话:
d = dict((row[8], row) for row in reader)
假设你有这样的输入文件:
John, Smith, 2, 3, 4, 5, 6, 7, 8, 9, 10
Ed, Jones, 20, 30, 40, 50, 60, 70, 80, 90, 100
你会得到这样的字典:
{'8': ['John', 'Smith', '2', '3', '4', '5', '6', '7', '8', '9', '10'],
'80': ['Ed', 'Jones', '20', '30', 40', '50', '60', '70', '80', '90', '100']}
* 这里假设第8列的值是唯一的。否则,这样做就没有意义了。你可能还想要一个多重字典,把每个第8列的值映射到所有包含该值的行的列表,或者一个字典,把每个第8列的值映射到一个“多行”数据,这个数据把所有包含该值的行的每列值组合在一起,或者……谁知道呢。只要你理解了基本思路,并知道自己想要哪个,这些都很容易实现。
编辑 --> 根据提问者的评论,我觉得这更符合他们的需求(使用DictReader会简单很多):
import csv
with open('c:\us-500.csv', 'rU') as f:
reader = csv.DictReader(f)
address_book = {}
for row in reader:
address_book[row['phone1']] = row
这个代码会生成一个字典,字典的主键是文件中的第八列“phone1”。你可以这样访问里面的值。
address_book['555-1212']['first_name']
address_book['978-3425']['email']
编辑2 --> 现在删除原来的回答。基本上,原来的回答是在重新实现DictReader的功能。