python - 有没有更快的方法来合并 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
我们可以将原始的“扁平化”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_all
从dict_current
我们应用flatter
到每个,使用set.update
,然后将其转换为数据框并使用groupby.aggregate
将其转换回 a dict
of set
。
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 个字典条目。原始循环方法大约需要 4ms。另一种单片更新方法大约需要 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)
推荐阅读
- vb.net - 在 List(of Point) 中查找当前 y 的 2 个 x 值
- javascript - 在 Javascript 测验中使用之前标记的完整选项随机回答问题
- reactjs - 在条件匹配的 api id 后,我无法在 dom 中显示数据
- python - Discord Py 需要在后台默默地给我的机器人角色
- html - 从 JSON 中获取输入字段
- c# - 我是否需要担心 Rx.NET FromEventPattern 的内存泄漏?
- javascript - 检索列在 nodeList 中的 jsFunction 的参数
- r - 有没有办法指定要在热图中返回的 kmeans 集群的数量
- python - 用模糊规范化列的字符串
- python - 来自未知节点的请求张量连接:“dense_5_target:0”