2016-05-25 2 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 'и '" Б "= 2', а не' "B" => 3'. Это ошибка/опечатка? (так как 'collect (1: 1: 3) == [1,2,3]') –

+1

Исправлено, извините. Я ненавидел текстовый редактор stackoverflow и хотел как можно скорее выбраться из него: D – Nico202

ответ

3

Следующий фрагмент воспроизводит результат в примере и может служить основой для других вариантов, которые относятся к рекурсии по-разному (есть много вариантов, как я заметил при попытке этого). Он использует Iterators.jl, который установлен с 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 

И пример:

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

Смежные вопросы