5

假设有以下玩具(来自一个 CSV 文件,其中列名是“键”,我只对放入“数据”的某些行感兴趣):

keys = ['k1', 'k2', 'k3', 'k4']
data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]

我想得到一个字典,每列都有一个列表,如下所示:

{'k1': [1, 5, 9, 13], 'k2': [2, 6, 10, 14], 'k3': [3, 7, 11, 15], 'k4': [4, 8, 
12, 16]}

在我的代码中,我首先使用空列表初始化字典,然后迭代(按键的顺序)以将每个项目附加到列表中。

my_dict = dict.fromkeys(keys, [])
for row in data:
    for i, k in zip(row, keys):
        my_dict[k].append(i)

但它不起作用。它构建了这个字典:

{'k3': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], 'k2': [1, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], 'k1': [1, 2, 3, 4, 5, 6, 7, 8, 
9, 10, 11, 12, 13, 14, 15, 16], 'k4': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
13, 14, 15, 16]}

您可以看到所有元素都在所有列表中,而不是每个列表中只有四个元素。如果我在循环中打印 i, k 它会执行正确的项目和键对。所以我想问题是当我在键 k 的列表中添加项目 i 时。

有谁知道为什么所有元素都添加到所有列表中,以及构建我的字典的正确方法是什么?

提前致谢

4

5 回答 5

9

压缩它,但先转置它:

>>> keys = ['k1', 'k2', 'k3', 'k4']
>>> data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
>>> print dict(zip(keys, zip(*data)))
{'k3': (3, 7, 11, 15), 'k2': (2, 6, 10, 14), 'k1': (1, 5, 9, 13), 'k4': (4, 8, 12, 16)}

如果您想要列表而不是数组中的元组:

>>> print dict(zip(keys, [list(i) for i in zip(*data)]))

如果您想使用您的版本,只需进行字典理解,而不是fromkeys

my_dict = { k : [] for k in keys }

my_dict使用相同值初始化的问题:

>>> my_dict = dict.fromkeys(keys, [])
>>> my_dict
{'k3': [], 'k2': [], 'k1': [], 'k4': []}
>>> my_dict['k3'].append(1)
>>> my_dict
{'k3': [1], 'k2': [1], 'k1': [1], 'k4': [1]}

当你做对时(使用字典/列表理解):

>>> my_dict = dict((k, []) for k in keys )
>>> my_dict
{'k3': [], 'k2': [], 'k1': [], 'k4': []}
>>> my_dict['k3'].append(1)
>>> my_dict
{'k3': [1], 'k2': [], 'k1': [], 'k4': []}
于 2012-07-23T13:23:06.693 回答
7

您遇到了此答案中解释的问题:您的字典已使用为所有值重新使用的相同列表对象进行初始化。只需使用

dict(zip(keys, zip(*data)))

反而。这会将行列表转换为列列表,然后将键和列压缩在一起。

于 2012-07-23T13:16:49.477 回答
4

我认为这dict(zip(keys, map(list,zip(*data)) ))应该可以解决问题。

首先,我转置你的数据(zip(*data)),但返回元组......因为你想要列表,我使用 map 从元组构造列表。然后我们再次使用 zip 将键与列表中的项目匹配。例如(key1,list1), (key2,list2),...。这正是字典构造函数所期望的,所以你是金子。

另一种解决方案是使用collections.defaultdict

d=collections.defaultdict(list)
tdata=zip(*data)  #transpose your data
for k,v in zip(keys,tdata):
    d[k].extend(v)

当然,这会给您留下一个 defaultdict 而不是常规的,尽管它可以轻松地更改为常规的 d=dict(**d)

于 2012-07-23T13:16:40.860 回答
0

那应该工作:

keys = ['k1', 'k2', 'k3', 'k4']
data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
mydict = {}
for k in keys:
    b[k] = []
    for l in data:
        b[k].append(l[i])
    i += 1

请注意, index() 是一个昂贵的函数。当你有一个庞大的数据集时不要使用它。在这种情况下增加一个变量。

编辑:不,它没有!抱歉,请稍等

编辑:现在可以了!

于 2012-07-23T13:19:28.597 回答
0
>>> keys = ['k1', 'k2', 'k3', 'k4']
>>> data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
>>> dict(zip(keys, zip(*data)))
{'k3': (3, 7, 11, 15), 'k2': (2, 6, 10, 14), 'k1': (1, 5, 9, 13), 'k4': (4, 8, 12, 16)}

如果你真的需要列表:

>>> dict(zip(keys, map(list, zip(*data))))
{'k3': [3, 7, 11, 15], 'k2': [2, 6, 10, 14], 'k1': [1, 5, 9, 13], 'k4': [4, 8, 12, 16]}

如果您使用的是 python 2,则zip返回maps list。如果您正在使用大型数据集,您可以使用itertools.izipitertools.imap提高效率并避免创建中间列表。

于 2012-07-23T13:22:43.610 回答