如何将键值对元组列表转换为字典?

140
  • Item 1
  • Item 2
  • Item 3

How can I remove a specific item from this list in Python?

[('A', 1), ('B', 2), ('C', 3)]

我想把它转换成一个类似以下的字典:

{'A': 1, 'B': 2, 'C': 3}

怎样最好地解决这个问题?

编辑:我的元组列表实际上更像是:

[(A, 12937012397), (BERA, 2034927830), (CE, 2349057340)]

我遇到了错误ValueError: dictionary update sequence element #0 has length 1916; 2 is required


1
这些 AB(或 BERA)和 C(或 CE)到底是什么实体?谢谢。 - eat
我愿意打赌,下面的工作示例中产生的错误与他没有一个元组列表有关,而是一个他想要分成2元组的极长列表。 - g.d.d.c
7个回答

179
>>> dict([('A', 1), ('B', 2), ('C', 3)])
{'A': 1, 'C': 3, 'B': 2}

6
也在另一个建议相同的答案上发表了评论:这并不涵盖具有重复元组“键”的情况,例如:l=[('A',1), ('B',2), ('C',3), ('A', 2)]将导致有 'A':1,这可能不是所需的结果。 - gdvalderrama

97

你的错误:

为什么会出现ValueError: dictionary update sequence element #0 has length 1916; 2 is required错误:

答案是你的列表元素不是你想象的那样。如果你输入myList[0],你会发现你的列表的第一个元素不是一个二元组,例如('A', 1),而是一个长度为1916的可迭代对象。

一旦你真正地拥有了你在原始问题中所述的形式的列表(myList = [('A',1),('B',2),...]),你只需要执行dict(myList)即可。


总体而言:

要么使用通常的dict(iterableOrMapping)构造函数,要么使用字典推导式{someExpr(k,v) for k:v in iterable}语法:

>>> example1 = [('A',1), ('B',2), ('C',3)]
>>> dict(example1)
{'A': 1, 'B': 2, 'C': 3}

>>> {x:x**2 for x in range(3)}
{0: 0, 1: 1, 2:4}

# inline; same as example 1 effectively. may be an iterable, such as
# a sequence, evaluated generator, generator expression

>>> dict( zip(range(2),range(2)) )
{0: 0, 1: 1, 2:2}

一个Python字典是一个无序的集合,其可以进行O(1)搜索,包含一系列键值对{(key→value), ...},其中键可以是任何不可变对象,值可以是任何对象。

为了在字典中使用键,键必须实现.__eq__().__hash__()方法。如果你正在考虑实现它,那么你可能正在做一些错误的事情,应该考虑使用其他映射数据结构!(尽管有时你可以通过将键包装在不同的包装器结构中并使用常规字典来解决问题,但这可能不是理想的)

希望实现“冻结”或“不可变”类型,或者伪装成这种类型的中级或高级程序员必须非常小心,否则您的程序将出现极其微妙且几乎不可能找到的错误

如果您允许稍后更改对象的相等概念,以使其发生变化,则无法使用字典。被视为相等的对象必须始终返回True,并且具有相同的__hash__值。

这些方法必须完全遵守规范。这意味着:

  • 对于初学者:哈希函数(wikip.)让您获得假阳性或真阳性结果;hash(x)==hash(y) 意味着 x 可能等于 y,然后内部 Python 代码必须检查 x==y.__eq__)以确认它是真阳性而不是假阳性。这允许 O(1) 查找。
  • 对于初学者:非常重要的是,一旦对象处于最终状态,__hash__ 值不应因任何原因而更改。如果您无法保证这一点和 hash(x)!=hash(y) implies x!=y,则不应使用字典。
  • 可以考虑使用 不同类型的映射而不是修改数据本身。这可能相当于编写包装器对象,代价是使用库。通常情况下不需要这样做。
  • 对于专家:还应注意,某些默认对象的哈希值是加盐的,并且可能在 Python 启动和版本之间发生变化(如果以包含 Python 哈希的方式存储或网络通信数据,则可能会出现问题;它们是内部细节,应在每个进程启动时重新生成)。

Python有许多内置的冻结数据结构,如namedtuplefrozenset等,但它们有时更难处理。 tuple是基本的冻结变体,与基本的list结构相同(允许您存储{(1, 2): 3, (4, 5): 6})。 它还具有dict结构的一些变体。 如果您想从“冻结字典”获取映射到值的映射,则除了作为第三方库的frozendict之外,不存在,但您可以将字典的.items()提取为无序的frozensettuple


谢谢,我不知道列表是怎么变成那样的,但是重新从头开始重构后,我成功修复了它。 - Fred Wilson
1
@DJ_Stuffy_K: 一般来说,除非它是多余的或减慢程序速度,否则创建字典作为隐式构建的任何抽象数据结构的有用索引是完全可以的。 "良好实践" 的概念完全取决于上下文; 您需要O(1)查找键吗?此外,您不能任意地“将列表转换为字典”; 它完全取决于语义。例如,[(1,2), (1,3)] -> {1:3}会破坏您的键并且丢失信息!字典是具有O(1)插入/删除时间的一对多关系。列表是一个列表。 - ninjagecko

34

你尝试过这个吗?

>>> l=[('A',1), ('B',2), ('C',3)]
>>> d=dict(l)
>>> d
{'A': 1, 'C': 3, 'B': 2}

值错误:字典更新序列的第0个元素长度为1916,需要2个。 - Fred Wilson
那是我从终端直接复制粘贴的,所以应该可以工作。你能具体展示一下你做了什么来导致出现那个错误吗? - Useless
@chacham15 , ..., string1916]) - OJFord
2
这并不包括具有重复元组“键”的情况,例如:l=[('A',1), ('B',2), ('C',3), ('A', 2)]将导致具有'A': 1的结果,这可能不是期望的结果。 - gdvalderrama
你是否在猜测一年前的问题可能需要添加什么要求?原帖作者已经接受了一个答案,可以假定他比你更清楚所需的结果是什么。 - Useless
显示剩余2条评论

13

以下是处理重复元组"键"的方法:

# An example
l = [('A', 1), ('B', 2), ('C', 3), ('A', 5), ('D', 0), ('D', 9)]

# A solution
d = dict()
[d [t [0]].append(t [1]) if t [0] in list(d.keys()) 
 else d.update({t [0]: [t [1]]}) for t in l]
d

OUTPUT: {'A': [1, 5], 'B': [2], 'C': [3], 'D': [0, 9]}

太棒了!帮了我一个大忙。 - unpairestgood
太好了!帮了很大的忙。 - Athar

9

如果元组中没有键的重复,那么它就是简单的。

tup = [("A",0),("B",3),("C",5)]
dic = dict(tup)

如果元组中有键的重复。

tup = [("A",0),("B",3),("C",5),("A",9),("B",4)]
dic = {}
for i, j in tup:
    dic.setdefault(i,[]).append(j)

或者:

from collections import defaultdict
tup = [("A",0),("B",3),("C",5),("A",9),("B",4)]
dic = defaultdict(list)
for i, j in tup:
    dic[i].append(j)

我仍然不明白setdefault做什么,你能帮我吗? - Ariel Marcelo Pardo
1
@ArielMarceloPardo setdefault(不可理解的名称)返回字典中给定的元素,但如果不存在,则使用默认值参数(在本例中为[],即空列表)创建它并返回它。因此,如果字典中的i键尚不存在,则创建它并将一个空列表作为值,然后将值j附加到该列表。如果键已经存在,则将j附加到该索引处的列表中。话虽如此,在这种情况下,defaultdict是一个更好的选择,但只是因为没有办法想出比难以理解的setdefault更好的名称。 - Antonio

4

使用字典推导式的另一种方法:

>>> t = [('A', 1), ('B', 2), ('C', 3)]
>>> d = { i:j for i,j in t }
>>> d
{'A': 1, 'B': 2, 'C': 3}

1
l=[['A', 1], ['B', 2], ['C', 3]]
d={}
for i,j in l:
d.setdefault(i,j)
print(d)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接