2016-05-25 12 views
5

julia他の辞書、文字列/数字のリスト、辞書のリスト、文字列/数字、範囲を含む辞書があります。範囲を含む辞書のすべての組み合わせを生成

それに含まれているすべての範囲(StepRange、FloatRange、UnitRangeなど)のすべての可能な辞書の組み合わせを含むリストが必要です。

例:今

Dict{}("A" => Dict{}("B" => 1:1:3, "C" => 2), "B" => [Dict{}("S" => 1:1.1:2.1)]) 

=>

[ 
Dict{}("A" => Dict{}("B" => 1, "C" => 2), "B" => [Dict{}("S" => 1.1)]), 
Dict{}("A" => Dict{}("B" => 2, "C" => 2), "B" => [Dict{}("S" => 1.1)]), 
Dict{}("A" => Dict{}("B" => 3, "C" => 2), "B" => [Dict{}("S" => 1.1)]), 
Dict{}("A" => Dict{}("B" => 1, "C" => 2), "B" => [Dict{}("S" => 2.1)]), 
Dict{}("A" => Dict{}("B" => 2, "C" => 2), "B" => [Dict{}("S" => 2.1)]), 
Dict{}("A" => Dict{}("B" => 3, "C" => 2), "B" => [Dict{}("S" => 2.1)]) 
] 

、私はこのような再帰関数をオーバーロードするが、継続する方法については考えていますよ。

function iterate(generic, nets::Array) 
    return (generic, false) 
end 

function iterate(range::Union{StepRange,FloatRange,UnitRange}, nets::Array) 
    return (collect(range), true) 
end 

function iterate(array::Array, nets::Array) 
    for (n, v) in enumerate(array) 
     res = iterate(v, nets) 
     if res[2] 
      ## We found a range! Return it 
      return res 
     end 
    end 
    return (array, false) 
end 

function iterate(dict::Dict, nets::Array) 
    for (k, v) in dict 
     res = iterate(v, nets) 
     if res[2] 
      return (dict, true) 
     end 
    end 
    return (dict, false) 
end 

は(私はすでにpythonでこれを行っているが、()「[1,2,0.1]」のようなカスタム定義の範囲を見つけるために正規表現を使用して、テキストの一部に取り組んやテキストコードの解析を生成した後)

+1

、 ' "B"=> 1:1:3'出力リスト一方のみ' "B" => 1 'と' "B "= 2"であり、 "B" => 3 "ではない。これはバグですか? ( 'collect(1:1:3)== [1,2,3]'以降) –

+1

修正済み、申し訳ありません。私はstackoverflowテキストエディタを嫌っていて、できるだけ早くそこから抜け出したいと思っていました:D – Nico202

答えて

3

次のスニペットは、例の出力を再現し、再帰を別の方法で処理する他のバリアントの基礎となる可能性があります(これを試したときに気づいたように、多くのオプションがあります)。 Pkg.add("Iterators")がインストールされたIterators.jlを使用しています。

using Iterators 

function findranges{K}(sd::Dict{K}) 
    ranges = Vector{Vector}() 
    for v in values(sd) 
    if isa(v,Range) 
     push!(ranges,collect(v)) 
    elseif isa(v,Dict) 
     push!(ranges,recdictcollect(v)) 
    elseif isa(v,Vector) 
     push!(ranges,map(x->vcat(x...),collect(product(map(recdictcollect,v)...)))) 
    end 
    end 
    ranges 
end 

function recdictcollect{K}(sd::Dict{K}) 
    ranges = findranges(sd) 
    if length(ranges)==0 
    cases = [()] 
    else 
    cases = product(ranges...) |> collect 
    end 
    outv = Vector{Dict{K,Any}}() 
    for c in cases 
    newd = Dict{K,Any}() 
    i = 1 
    for (k,v) in sd 
     if any([isa(v,t) for t in [Range,Dict,Vector]]) 
     newd[k] = c[i] 
     i += 1 
     else 
     newd[k] = v 
     end 
    end 
    push!(outv,newd) 
    end 
    return outv 
end 

及び実施例:実施例で

julia> example = Dict{}("A" => Dict{}("B" => 1:1:3, "C" => 2), "B" => [Dict{}("S" => 1:1.1:2.1)]) 
Dict{ASCIIString,Any} with 2 entries: 
    "B" => [Dict("S"=>1.0:1.1:2.1)] 
    "A" => Dict{ASCIIString,Any}("B"=>1:1:3,"C"=>2) 

julia> recdictcollect(example) 
6-element Array{Dict{ASCIIString,Any},1}: 
Dict{ASCIIString,Any}("B"=>[Dict{ASCIIString,Any}("S"=>1.0)],"A"=>Dict{ASCIIString,Any}("B"=>1,"C"=>2)) 
Dict{ASCIIString,Any}("B"=>[Dict{ASCIIString,Any}("S"=>2.1)],"A"=>Dict{ASCIIString,Any}("B"=>1,"C"=>2)) 
Dict{ASCIIString,Any}("B"=>[Dict{ASCIIString,Any}("S"=>1.0)],"A"=>Dict{ASCIIString,Any}("B"=>2,"C"=>2)) 
Dict{ASCIIString,Any}("B"=>[Dict{ASCIIString,Any}("S"=>2.1)],"A"=>Dict{ASCIIString,Any}("B"=>2,"C"=>2)) 
Dict{ASCIIString,Any}("B"=>[Dict{ASCIIString,Any}("S"=>1.0)],"A"=>Dict{ASCIIString,Any}("B"=>3,"C"=>2)) 
Dict{ASCIIString,Any}("B"=>[Dict{ASCIIString,Any}("S"=>2.1)],"A"=>Dict{ASCIIString,Any}("B"=>3,"C"=>2)) 
+0

実世界の例では、recdictcollect(sd :: Int)= sdを追加する必要がありましたが、これは間違いなくトリックです! ありがとう – Nico202

関連する問題