2016-05-25 26 views
5

In julia ho un dizionario che può contenere altri dizionari, elenchi di stringhe/numeri, elenchi di dizionari, stringhe/numeri e intervalli.Genera tutte le combinazioni di dizionari contenenti intervalli

Ho bisogno di un elenco contenente tutta la combinazione possibile di dizionari per ogni intervallo (come StepRange, FloatRange, UnitRange) in esso contenuto.

Esempio:

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)]) 
] 

In questo momento, mi sto sovraccaricare una funzione ricorsiva come questo, ma non hanno idea su come continuare.

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 

(ho già fatto in Python, ma lavorare su un pezzo di testo, usando espressioni regolari per trovare campi di misura definiti (come "[1,2,0.1]") e dopo la generazione del codice di testo di analisi it.)

+1

Nell'esempio, ' "B"=> 1: 1: 3' mentre solo le liste di uscita' "B" => 1' e '" B "= 2' e non' "B" => 3'. È un errore/errore di battitura? (poiché 'collect (1: 1: 3) == [1,2,3]') –

+1

Risolto, scusa. Stavo odiando l'editor di testo StackOverflow e volevo uscirne al più presto possibile: D – Nico202

risposta

3

Il seguente snippet riproduce l'output nell'esempio e potrebbe servire come base per altre varianti che trattano la ricorsione in modo diverso (ci sono molte opzioni, come ho notato quando ho provato questo fuori). Si utilizza Iterators.jl che viene installato con Pkg.add("Iterators").

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 

E l'esempio:

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

Nell'esempio del mondo reale ho dovuto aggiungere: recdictcollect (sd :: Int) = sd, ma questo sicuramente fa il trucco! Grazie – Nico202

Problemi correlati