在Python中使用zip或dict函数将列表转换为字典

-1 投票
5 回答
3731 浏览
提问于 2025-04-28 00:20

经过多次尝试,我终于写出了下面的代码,可以从一个特定的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 个回答

0

你可以使用 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}
0

如果你能把数据整理成两个列表(并且这两个列表的顺序是你想要的),那么你就可以准备把它们转换成字典了。

>>> 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'}
0

根据你的评论,听起来你想要的是这样的东西:

  • 一系列的行。
  • 一个或多个“索引”多字典,用来把某一列的值和拥有这个值的行号对应起来。

所谓的“多字典”,就是一种字典,它把键映射到某种集合,比如集合或列表。你可以很简单地通过使用 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)

所以,现在如果你想找到所有 phone1phone21.555.555.1212 的人的姓氏:

matches = phone1_map['1.555.555.1212'] | phone2_map['1.555.555.1212']
names = {match.name for match in matches}
1

我来猜猜你想要的是什么。

你有一个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列的值映射到一个“多行”数据,这个数据把所有包含该值的行的每列值组合在一起,或者……谁知道呢。只要你理解了基本思路,并知道自己想要哪个,这些都很容易实现。

0

编辑 --> 根据提问者的评论,我觉得这更符合他们的需求(使用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的功能。

撰写回答