julia – 如何制作更强大的拉链/解压缩?

我有一个数组{元组{A,B}},我想将其解压缩/转置为元组{Array {A},Array {B}}.

typealias MyIndexType Tuple{Bool, Int}

function test(x::MyIndexType)
    # prepare for test data set.
    myArray = Array{Tuple{MyIndexType, Float64}}(0)
    push!(myArray, (x,1))
    push!(myArray, (x,1))
    push!(myArray, (x,1))

    # transform
    a, b = (zip(myArray...)...)
    [a...]
end

test((true, 1))

>>>
3-element Array{Tuple{Bool,Int64},1}:
(true,1)
(true,1)
(true,1)

但是,使用@code_warntype,JIT无法提前推断a,b的类型.

Variables:
  x::Tuple{Bool,Int64}
  myArray::Array{Tuple{Tuple{Bool,Int64},Float64},1}
  a::ANY
  b::ANY
  #s41::Int64

Body:
  begin  # In[47], line 6:
      myArray = (top(ccall))(:jl_alloc_array_1d,(top(apply_type))(Base.Array,Tuple{Tuple{Bool,Int64},Float64},1)::Type{Array{Tuple{Tuple{Bool,Int64},Float64},1}},(top(svec))(Base.Any,Base.Int)::SimpleVector,Array{Tuple{Tuple{Bool,Int64},Float64},1},0,0,0)::Array{Tuple{Tuple{Bool,Int64},Float64},1} # In[47], line 7:
      (Main.push!)(myArray::Array{Tuple{Tuple{Bool,Int64},Float64},1},(top(tuple))(x::Tuple{Bool,Int64},1)::Tuple{Tuple{Bool,Int64},Int64})::Array{Tuple{Tuple{Bool,Int64},Float64},1} # In[47], line 8:
      (Main.push!)(myArray::Array{Tuple{Tuple{Bool,Int64},Float64},1},(top(tuple))(x::Tuple{Bool,Int64},1)::Tuple{Tuple{Bool,Int64},Int64})::Array{Tuple{Tuple{Bool,Int64},Float64},1} # In[47], line 9:
      (Main.push!)(myArray::Array{Tuple{Tuple{Bool,Int64},Float64},1},(top(tuple))(x::Tuple{Bool,Int64},1)::Tuple{Tuple{Bool,Int64},Int64})::Array{Tuple{Tuple{Bool,Int64},Float64},1} # In[47], line 10:
      GenSym(0) = (top(_apply))((top(getfield))(Main,:call)::F,top(tuple),(top(_apply))((top(getfield))(Main,:call)::F,Main.zip,myArray::Array{Tuple{Tuple{Bool,Int64},Float64},1})::UNION{BASE.ZIP2{TUPLE{TUPLE{BOOL,INT64},FLOAT64},TUPLE{TUPLE{BOOL,INT64},FLOAT64}},TUPLE{TUPLE{BOOL,INT64},FLOAT64},ZIP{I,Z<:BASE.ABSTRACTZIPITERATOR}})::TUPLE
      #s41 = 1
      GenSym(4) = (Base.getfield)(GenSym(0),1)::ANY
      GenSym(5) = (Base.box)(Base.Int,(Base.add_int)(1,1)::ANY)::Int64
      a = GenSym(4)
      #s41 = GenSym(5)
      GenSym(6) = (Base.getfield)(GenSym(0),2)::ANY
      GenSym(7) = (Base.box)(Base.Int,(Base.add_int)(2,1)::ANY)::Int64
      b = GenSym(6)
      #s41 = GenSym(7) # In[47], line 11:
      return (top(_apply))((top(getfield))(Main,:call)::F,top(vect),a)::ANY
  end::ANY

有没有办法让zip知道结果类型?

更新

实际上有2个问题.

>它认为a类型为a :: TUPLE {UNION {FLOAT64,INT64},UNION {FLOAT64,INT64}},但它实际上是类型a :: TUPLE {FLOAT64,FLOAT64}

function test{T}(x::T)
    A = Tuple{T, Int}[]

    for i in 1:3
        push!(A, (x, 1))
    end

    d = zip(A[1], A[2])
    a, b = d
    a
end

@code_warntype test(3.0)


Variables:
  x::Float64
  A::Array{Tuple{Float64,Int64},1}
  d::Base.Zip2{Tuple{Float64,Int64},Tuple{Float64,Int64}}
  a::TUPLE{UNION{FLOAT64,INT64},UNION{FLOAT64,INT64}}
  b::TUPLE{UNION{FLOAT64,INT64},UNION{FLOAT64,INT64}}
  #s40::Tuple{Int64,Int64}
  #s41::Int64
  i::Int64

>对于带有2个以上参数的zip,注意d有一个嵌套的zip2类型,我觉得这可能会给类型推断带来负担.

function test{T}(x::T)
    A = Tuple{T, Int}[]

    for i in 1:3
        push!(A, (x, 1))
    end

    d = zip(A[1], A[2], A[3])
    a, b = d
    a
end

@code_warntype test(3.0)

Variables:
  x::Float64
  A::Array{Tuple{Float64,Int64},1}


  d::Zip{Tuple{Float64,Int64},Base.Zip2{Tuple{Float64,Int64},Tuple{Float64,Int64}}}
  a::TUPLE{UNION{FLOAT64,INT64},UNION{FLOAT64,INT64},UNION{FLOAT64,INT64}}
  b::TUPLE{UNION{FLOAT64,INT64},UNION{FLOAT64,INT64},UNION{FLOAT64,INT64}}
  #s40::Tuple{Int64,Tuple{Int64,Int64}}
  #s41::Int64
  i::Int64
  ##c#7879::Tuple{Tuple{Float64,Int64}}

我为什么要关心这种类型?

编译以下示例的a,b = zip(A …)需要10秒钟,速度似乎与A的长度有关.(Julia 0.4)

const A = Tuple{Int, Int}[]

for i = 1:200
    push!(A, (1, 1))
end

a, b = zip(A...)
a

我在这里打开了一个错误报告https://github.com/JuliaLang/julia/issues/13722

最佳答案 我相信,@ code_warntype报告说,如果它最终得到正确的类型,它就无法推断出正确的类型.

我仍然想知道这是否是由于你的类型的复杂性.但它不是,如下面的代码所示(具有更简单的类型).

请注意,您还可以简化您的zip表达式;而且您可能不需要将a转换为数组.

码:

function test{T}(x::T)
    A = Tuple{T, Int}[]

    for i in 1:3
        push!(A, (x, 1))
    end

    a, b = zip(A...)
    a, b
end

julia> test(3)  # now returns a and b
((3,3,3),(2,2,2))   

julia> @code_warntype test(3)
Variables:
  x::Int64
  A::Array{Tuple{Int64,Int64},1}
  a::ANY
  b::ANY
  #s40::ANY
  #s41::Int64
  i::Int64
点赞