繁体   English   中英

有没有更快的方法来合并 python 中的两个集合字典?

[英]Is there a faster way to merge two dicts of sets in python?

dict_current 和 dict_all 是两个以集合为值的字典。 我想将 dict_current 中的任何内容合并到 dict_all 中。 测试代码如下:

value_1 = {('x', 1),('y', 2), ('z',3)}
value_2 = {('x', 8),('y', 2), ('z',3)}
value_3 = {('x', 11)}

dict_current = {'a': value_1}
dict_all = {'a': value_2, 'b': value_3}

for k, v in dict_current.items():
    if k in dict_all:
        dict_all[k].update(v)
    else:
        dict_all[k] = v

print(dict_all)

如果 dict_current 很大,for 循环每次合并都需要相当长的时间。 有没有更快的方法来实现这种合并?

这是不是更快的东西。

我们可以将原始的dict of set “扁平化”为一set元组,将每个原始键与该键的每个 set 成员(它们本身是较低级别的元组)配对。 这保留了每个原始键与一个或多个元组相关联的限制(这些较低级别的元组可以在不同键之间重复,但不能在特定键内重复)。

def flatter(dict_data):
    # Return set with each dict key paired with each member of key's value.
    return set((k, member) for k, v in dict_data.items() for member in v)

flatter({'a': value_2, 'b': value_3})
# {('a', ('x', 1)),
#  ('a', ('x', 8)),
#  ('a', ('y', 2)),
#  ('a', ('z', 3)),
#  ('b', ('x', 11))}

现在要从dict_current更新dict_all ,我们对每个应用flatter ,使用set.update ,然后将其转换为 dataframe 并使用groupby.aggregate将其转换回setdict

import pandas as pd

def updater2(dict_all, dict_current):
    # Alternative single monolithic update.

    # Explode key-set pairs into set of key-member pairs.
    flatter_all = flatter(dict_all)

    # Update from current key-member pairs.
    flatter_all.update(flatter(dict_current))

    # Assemble set for each key from key-member pairs.
    return pd.DataFrame.from_records(list(flatter_all), columns=["k", "v"]) \
                .groupby("k").aggregate(set)["v"].to_dict()

为了比较速度,我们可能会尝试大约 10,000 个字典条目。 原始循环方法大约需要 4 毫秒。 替代的单片单次更新方法大约需要 260 毫秒,大约长 65 倍。 哎哟!

def updater1(dict_all, dict_current):
    # Original loop over current and update if already in all.
    for k, v in dict_current.items():
        if k in dict_all:
            dict_all[k].update(v)
        else:
            dict_all[k] = v

# 10,000 entries in current, plus a handful more in all.
size = 10000
data_current = {n: value_1 for n in range(size)}
data_all = {n: value_2 if n < size else value_3 for n in range(size+5)}

# Time original.
%timeit updater1(data_all, data_current)
# 3.69 ms ± 92.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)


# Set up data again since updater1 modifies data_all.
data_current = {n: value_1 for n in range(size)}
data_all = {n: value_2 if n < size else value_3 for n in range(size+5)}

# Time alternative single monolithic update.
%timeit updater2(data_all, data_current)
# 257 ms ± 20.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

即使我们预先扁平化字典并仅将我们的数据保持在更扁平的形式,它也不会超过原始的速度。 这大约需要 9 毫秒,是原始算法在此测试数据上所需时间的两倍多。

def updater3(flatter_all, flatter_current):
    # Update set flatter_all from set flatter_current.
    flatter_all.update(flatter_current)

# 10,000 entries in current, plus a handful more in all.
flatter_current = flatter({n: value_1 for n in range(size)})
flatter_all = flatter({n: value_2 if n < size else value_3
                       for n in range(size+5)}
                      )

# Time single monolithic update of flattened set.
%timeit updater3(flatter_current, flatter_all)
# 8.68 ms ± 738 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM