How to make stronger typed zip / unzip?

I have Array{Tuple{A, B}}and I want to unzip / move it to Tuple{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)

However, using @code_warntype, the JIT can not infer the type a, bahead of time.

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

Is there a way to make zip aware of result types?

Update

There are actually two problems.

  • He thinks he ahas a type a::TUPLE{UNION{FLOAT64,INT64},UNION{FLOAT64,INT64}}, but he really has a typea::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
    
  • For ziptaking more than two arguments, note d has a nested type zip2, which, I feel, can carry the strain of type input.

    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}}
    

Why am I interested in type?

It takes 10 + seconds to compile a, b = zip (A ...) of the following example, and the speed seems to be related to the length of 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

+4
1

, , @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
+1

Source: https://habr.com/ru/post/1612664/


All Articles