【问题标题】:Fast conversion of a list with key-value with duplicate keys into a dictionary将具有重复键的键值列表快速转换为字典
【发布时间】:2020-04-01 12:19:55
【问题描述】:

在我的 Python 脚本中,我有一个列表 l,其中填充了成对的数字。我需要将它们转换为 dict 对象,将列表中的每个唯一数字作为键,并将键配对的数字列表作为值,因此:

输入:

l = [(1,2),
     (1,3),
     (2,3),
     (2,4),
     (5,4),
     (5,1)]

输出:

d = {1:[2,3,5],
     2:[1,3,4],
     3:[1,2],
     4:[2,5],
     5:[4,1]}

解决这个问题并不是一个新问题,例如见here

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]

不幸的是,如果l 变长(大约 10^6 对),这个解决方案就不够快。谁能想到一种更有效的方法?

【问题讨论】:

    标签: python


    【解决方案1】:

    您可以在此处使用defaultdict(list) 对键和值进行反向分组:

    from collections import defaultdict
    
    l = [(1,2),
         (1,3),
         (2,3),
         (2,4),
         (5,4),
         (5,1)]
    
    d = defaultdict(list)
    for x, y in l:
        d[x].append(y)
        d[y].append(x)
    
    print(d)
    # defaultdict(<class 'list'>, {1: [2, 3, 5], 2: [1, 3, 4], 3: [1, 2], 4: [2, 5], 5: [4, 1]})
    

    正如 @chepner 在 cmets 中指出的那样,您可以使用 defaultdict(set) 来处理反向元组,例如 (1, 5)(5, 1),因为会添加重复的对。

    d = defaultdict(set)
    for x, y in l:
        d[x].add(y)
        d[y].add(x)
    
    print(d)
    # defaultdict(<class 'set'>, {1: {2, 3, 5}, 2: {1, 3, 4}, 3: {1, 2}, 4: {2, 5}, 5: {1, 4}})
    

    时间复杂度

    上述解决方案将在O(N) 时间运行,因为它们需要扫描大小为N 的列表中的每一对。

    【讨论】:

    • 稍作调整,您可能想使用defaultdict(set),如果(1,5)(5, 1) 之类的配对可以在列表中。
    【解决方案2】:

    来自以下代码的时间:

    defaultdict 解决方案的持续时间:0:00:02.832145
    原始解决方案:0:00:02.925972
    持续时间: 0:00:02.401376

    所以你可以看到 defaultdict 会有所帮助,但大多数时候需要遍历列表。如果元素不重复,可以将类型改为set

    from collections import defaultdict
    from random import randrange
    from datetime import datetime
    
    
    def gen():
        for i in range(1000000):
            yield randrange(1, 5), randrange(1, 5)
    
    
    t1 = datetime.now()
    
    # defaultdict solution
    groups = defaultdict(list)
    for numbers in gen():
        groups[numbers[0]].append(numbers[1])
        groups[numbers[1]].append(numbers[0])
    
    t2 = datetime.now()
    print(f"Duration of defaultdict solution: {t2 - t1}")
    
    # original 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 gen()]
    t3 = datetime.now()
    print(f"Duration of original solution: {t3 - t2}")
    
    # through
    for numbers in gen():
        pass
    
    t4 = datetime.now()
    print(f"Duration of through: {t4 - t3}")
    

    【讨论】:

    • 感谢您的速度比较。这很有见地:)
    猜你喜欢
    • 2022-01-19
    • 2020-04-12
    • 2015-04-03
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多