有没有一种很好的方法来迭代字典中的键组合?
我的字典的值如下:
[1] => [1,2], [2,3] => [15], [3] => [6,7,8], [4,9,11] => [3], ...
我需要做的是获取长度为1:n
的所有密钥组合,其中n
可能是fx 3
所以在上面的例子中,我想迭代
[[1], [3], [2,3], [[1],[1,2]], [[3],[2,3]], [4,9,11]]
我知道我可以收集密钥,但我的字典相当大,我正在重新设计整个算法,因为它在n > 3
时开始疯狂交换,从而极大地降低了效率
tl; dr 有没有办法从没有collect
字典的字典中创建组合迭代器?
答案 0 :(得分:2)
以下是一个直接的实现,它试图通过字典最小化一点。此外,它使用OrderedDict,因此保持关键索引是有意义的(因为Dicts不承诺每次都进行一致的密钥迭代,因此有意义的密钥索引)。
using Iterators
using DataStructures
od = OrderedDict([1] => [1,2], [2,3] => [15], [3] => [6,7,8], [4,9,11] => [3])
sv = map(length,keys(od)) # store length of keys for quicker calculations
maxmaxlen = sum(sv) # maximum total elements in good key
for maxlen=1:maxmaxlen # replace maxmaxlen with lower value if too slow
@show maxlen
gsets = Vector{Vector{Int}}() # hold good sets of key _indices_
for curlen=1:maxlen
foreach(x->push!(gsets,x),
(x for x in subsets(collect(1:n),curlen) if sum(sv[x])==maxlen))
end
# indmatrix is necessary to run through keys once in next loop
indmatrix = zeros(Bool,length(od),length(gsets))
for i=1:length(gsets) for e in gsets[i]
indmatrix[e,i] = true
end
end
# gkeys is the vector of vecotrs of keys i.e. what we wanted to calculate
gkeys = [Vector{Vector{Int}}() for i=1:length(gsets)]
for (i,k) in enumerate(keys(od))
for j=1:length(gsets)
if indmatrix[i,j]
push!(gkeys[j],k)
end
end
end
# do something with each set of good keys
foreach(x->println(x),gkeys)
end
这比你现在拥有的更有效吗?将代码放在函数中或将其转换为Julia任务也会更好,每次迭代都会生成下一个键集。
---更新---
使用https://stackoverflow.com/a/41074729/3580870
中任务中的迭代器答案改进的迭代器版本是:
function keysubsets(n,d)
Task() do
od = OrderedDict(d)
sv = map(length,keys(od)) # store length of keys for quicker calculations
maxmaxlen = sum(sv) # maximum total elements in good key
for maxlen=1:min(n,maxmaxlen) # replace maxmaxlen with lower value if too slow
gsets = Vector{Vector{Int}}() # hold good sets of key _indices_
for curlen=1:maxlen
foreach(x->push!(gsets,x),(x for x in subsets(collect(1:n),curlen) if sum(sv[x])==maxlen))
end
# indmatrix is necessary to run through keys once in next loop
indmatrix = zeros(Bool,length(od),length(gsets))
for i=1:length(gsets) for e in gsets[i]
indmatrix[e,i] = true
end
end
# gkeys is the vector of vecotrs of keys i.e. what we wanted to calculate
gkeys = [Vector{Vector{Int}}() for i=1:length(gsets)]
for (i,k) in enumerate(keys(od))
for j=1:length(gsets)
if indmatrix[i,j]
push!(gkeys[j],k)
end
end
end
# do something with each set of good keys
foreach(x->produce(x),gkeys)
end
end
end
现在可以通过这种方式迭代所有密钥子集,直到组合大小为4(在运行其他StackOverflow答案的代码之后):
julia> nt2 = NewTask(keysubsets(4,od))
julia> collect(nt2)
10-element Array{Array{Array{Int64,1},1},1}:
Array{Int64,1}[[1]]
Array{Int64,1}[[3]]
Array{Int64,1}[[2,3]]
Array{Int64,1}[[1],[3]]
Array{Int64,1}[[4,9,11]]
Array{Int64,1}[[1],[2,3]]
Array{Int64,1}[[2,3],[3]]
Array{Int64,1}[[1],[4,9,11]]
Array{Int64,1}[[3],[4,9,11]]
Array{Int64,1}[[1],[2,3],[3]]
(从链接的StackOverflow答案中定义NewTask是必要的)。