我正在使用 Julia 1.9.0。
P
、Q
、R
和S
是键相同的字典,例如
P = Dict("a"=>1, "b"=>2, "c"=>3)
Q = Dict("a"=>2, "b"=>4, "c"=>2)
R = Dict("a"=>2, "b"=>4, "c"=>5)
S = Dict("a"=>4, "b"=>9, "c"=>1)
我想用相同键上的
P
、Q
、R
的总和覆盖字典 S
。我的意思是,我想得到
P = merge(+, [Q,R,S]...)
我们可以在不分配内存的情况下做到这一点吗?稍后我将使用字典
Q
、R
和 S
,因此它们不能被覆盖。但我不再需要P
了。这就是为什么只有 P
可以被覆盖。
我当前的代码
P = merge(+, [Q,R,S]...)
需要内存分配。我正在寻找没有(或更少)内存分配的替代方案。
using BenchamrkTools
@btime P = merge(+, [Q,R,S]...)
1.583 μs (10 allocations: 736 bytes)
编辑
为了简单起见,我只是描述了键数为3的情况。但实际上,键数约为10k,字典数量约为20。
这有效:
mergewith!(+, mergewith!((x,y)->y, P, Q), R, S)
内部
mergewith!
用 Q 覆盖 P,外部 mergewith!
添加其他 Dict 的值。
必须有一个预定义的函数
(x,y)->y
。评论里有人帮我...
编辑:由于 Gnimuc 和 BallpointBen 评论而改进:
mergewith!(+, merge!(P, Q), R, S)
啊,基准:
julia> @btime mergewith!(+, merge!($P, $Q), $R, $S);
100.487 ns (0 allocations: 0 bytes)
Dict{String, Int64} with 3 entries:
"c" => 8
"b" => 17
"a" => 8
如果字典是相同的具体类型,仍然可以提高效率。
添加:根据上面的评论,这是另一种获得可比速度的方法:
foreach(keys(P)) do k
P[k] = sum(D[k] for D in (Q,R,S))
end
对于鲁莽和寻求危险的人(想想赛车):
foreach(keys(P)) do k
index = Base.ht_keyindex(P, k)
P.vals[index] = sum(D.vals[index] for D in (Q,R,S))
end
这些基准:
julia> @btime foreach(keys($P)) do k
$P[k] = sum(D[k] for D in ($Q,$R,$S))
end
103.624 ns (0 allocations: 0 bytes)
julia> @btime foreach(keys($P)) do k
index = Base.ht_keyindex($P, k)
$P.vals[index] = sum(D.vals[index] for D in ($Q,$R,$S))
end
31.562 ns (0 allocations: 0 bytes)
也就是说,第一个是可比的,第二个要快得多(但关键取决于 Dict 实现和构造的相似性)。