【问题标题】:How to handle multiple keys for a dictionary in python?如何在python中处理字典的多个键?
【发布时间】:2018-05-29 08:27:15
【问题描述】:

如果发现重复键,我一直在寻找如何为 Dict 中的单个键添加多个 val。

举个例子:

list_1 = ['4', '6' ,'8', '8']
list_2 = ['a', 'b', 'c', 'd']
new_dict = dict(zip(list_1,list_2))
...output...
{'8': 'd', '4': 'a', '6': 'b'}

预期输出:

{'8': 'c,d', '4': 'a', '6': 'b'}

为了处理上述两个列表并将它们组合成一个字典,我将面临一定的挑战,我们不能在字典的“键”中包含两个 8,这是一种默认行为,我明白为什么! !

处理这种情况的一些选项是:

1) 查找dict中是否已经存在'key',如果存在,则将新的val附加到'key'

2) 创建一个可变对象来引用每个键,这样您就可以拥有多个 dup 键~~不是我的用例

那么,我怎样才能使用选项#1 获得预期的输出?

【问题讨论】:

  • 为什么不使用集合作为开始的值?
  • 为什么在列表更有意义时使用逗号分隔字符串?
  • 你想要一个defaultdict

标签: python list dictionary


【解决方案1】:

defaultdict/dict.setdefault

让我们开始吧:

  1. 连续迭代项目
  2. 附加属于同一键的字符串值
  3. 完成后,遍历每个键值对并将所有内容连接在一起以获得最终结果。

from collections import defaultdict

d = defaultdict(list)   
for i, j in zip(list_1, list_2):
    d[i].append(j)

defaultdict 使事情变得简单,并且在追加时效率很高。如果您不想使用defaultdict,请改用dict.setdefault(但这有点效率低下):

d = {}
for i, j in zip(list_1, list_2):
    d.setdefault(i, []).append(j)

new_dict = {k : ','.join(v) for k, v in d.items()})
print(new_dict)
{'4': 'a', '6': 'b', '8': 'c,d'}

熊猫DataFrame.groupby + agg

如果您想要大容量的性能,请尝试使用 pandas:

import pandas as pd

df = pd.DataFrame({'A' : list_1, 'B' : list_2})
new_dict = df.groupby('A').B.agg(','.join).to_dict()

print(new_dict)
{'4': 'a', '6': 'b', '8': 'c,d'}

【讨论】:

  • 这个过程快吗,我在每个列表中有大约 100 万条记录需要处理?
  • @PetPan 是的,这是这里最有效的解决方案。
  • 字典很快。
  • @PetPan 如果使用选项 1,请使用 defaultdict。如果还是太慢,试试我的 pandas 选项。
  • @U8-Forward 解决方案比 pandas 运行得更快有什么原因吗?
【解决方案2】:

您可以使用for 循环来遍历两个列表:

list_1 = ['4', '6' ,'8', '8']
list_2 = ['a', 'b', 'c', 'd']

new_dict = {}
for k, v in zip(list_1, list_2):
    if k in new_dict:
        new_dict[k] += ', ' + v
    else:
        new_dict[k] = v

大型词典可能存在效率问题,但在简单的情况下就可以正常工作。

感谢@Ev。 Kounis 和@bruno desthuilliers 指出了对原始答案的一些改进。


coldspeed 的回答比我的效率高,我把这个留在这里,因为它仍然是正确的,我看不出删除它的意义。

【讨论】:

  • 您可以通过使用字符串连接 (new_dict[k] += ', ' + v) 来避免多个 join 调用的浪费。你也可以简单地做if k not in new_dict 不调用它的keys() 方法。你也有错别字,
  • @coldspeed 是的,但比多次join 调用要好。
  • k not in dict.keys() 是 O(n)(它是一个顺序查找),而 k in dict 是 O(1)(它是一个哈希表键查找)并且高度优化。
  • 简短回答:我没有你那么好。 :) 有趣的事实:对于小型列表,此解决方案比您的更有效,coldspeed:使用 OPs 数据运行我的代码需要 1.88 +- 0.03 us,而您的代码需要 2.52 +- 0.09 us。随着列表大小为 1000,情况发生了变化:我的代码为 525 我们,而您的代码为 184。
【解决方案3】:

尝试使用setdefault字典函数并获取它的索引,然后使用try,除了检查idx是否存在之外,我没有每次都获取元素的索引,因为有重复并且在最后我对其进行格式化,使其输出类似于您想要的输出:

new_dict = {}
list_1 = ['4', '6' ,'8', '8']
list_2 = ['a', 'b', 'c', 'd']
for i in list_1:
   try:
      idx+=1
   except:
      idx = list_1.index(i)
   new_dict.setdefault(i, []).append(list_2[idx])
print({k:', '.join(v) for k,v in new_dict.items()})

输出:

{'4': 'a', '6': 'b', '8': 'c, d'}

【讨论】:

  • 我不敢相信,您的代码比 pandas 解决方案运行得更快。运行 Pandas 耗时 0.0160000324249 秒 运行其他耗时 0.0 秒
  • @PetPan 使用 timeit 进行准确计时。此外,您应该根据实际数据衡量性能,我可以立即告诉您,由于循环内的 .index 调用,这对于大型列表来说会非常慢。
  • 当然,您分享的内容很有意义,我正在寻找相同的信息。
猜你喜欢
  • 2021-11-03
  • 2023-03-22
  • 1970-01-01
  • 2011-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-23
相关资源
最近更新 更多