Create a whole combination of dictionaries containing ranges

In julia I have a dictionary that can contain other dictionaries, lists of strings / numbers, lists of dictionaries, strings / numbers and ranges.

I need a list containing all the possible combination of dictionaries for each range (e.g. StepRange, FloatRange, UnitRange) contained in it.

Example:

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

Right now I am overloading a recursive function like this, but I have no idea how to proceed.

 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 

(I already did this in python, but worked on a piece of text using a regular expression to search for custom ranges (for example, “[1,2,0.1]”) and after generating its parsing.)

+5
source share
1 answer

The following snippet reproduces the result in the example, and it can serve as the basis for other options that relate to recursion differently (there are many options, as I noticed when trying this). It uses Iterators.jl , which is installed with 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 

And an example:

 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)) 
+3
source

All Articles