在 Julia 中覆盖字典的值而不分配内存

问题描述 投票:0回答:1

我正在使用 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。

dictionary julia
1个回答
4
投票

这有效:

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 实现和构造的相似性)。

© www.soinside.com 2019 - 2024. All rights reserved.