Skip to content

Commit

Permalink
unzip: now with widening recursion trick
Browse files Browse the repository at this point in the history
  • Loading branch information
StefanKarpinski committed Oct 15, 2019
1 parent e64baab commit 4b839aa
Showing 1 changed file with 36 additions and 18 deletions.
54 changes: 36 additions & 18 deletions base/iterators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -426,28 +426,46 @@ julia> unzip([[1, "apple"], [2.5, "orange"], [0, "mango"]])
```
"""
function unzip(itrs)
n = Base.haslength(itrs) ? length(itrs) : -1
vecs = Vector[]
for itr in itrs
for (j, x) in enumerate(itr)
if length(vecs) < j
v = [x]
push!(vecs, v)
n 0 && sizehint!(v, n)
else
v = vecs[j]
if !(x isa eltype(v))
T = Base.promote_typejoin(typeof(x), eltype(v))
v = vecs[j] = copyto!(similar(v, T), v)
n 0 && sizehint!(v, n)
n = Base.haslength(itrs) ? length(itrs) : nothing
outer = iterate(itrs)
outer === nothing && return ()
vals, state = outer
vecs = ntuple(length(vals)) do i
x = vals[i]
v = Vector{typeof(x)}(undef, something(n, 1))
@inbounds v[1] = x
return v
end
unzip_rest(vecs, typeof(vals), n isa Int ? 1 : nothing, itrs, state)
end

function unzip_rest(vecs, eltypes, i, itrs, state)
while true
i isa Int && (i += 1)
outer = iterate(itrs, state)
outer === nothing && return vecs
itr, state = outer
vals = Tuple(itr)
if vals isa eltypes
for (v, x) in zip(vecs, vals)
if i isa Int
@inbounds v[i] = x
else
push!(v, x)
end
push!(v, x)
end
else
vecs′ = map(vecs, vals) do v, x
T = Base.promote_typejoin(eltype(v), typeof(x))
v′ = Vector{T}(undef, length(v) + !(i isa Int))
copyto!(v′, v)
@inbounds v′[something(i, end)] = x
return v′
end
eltypes′ = Tuple{map(eltype, vecs′)...}
return unzip_rest(Tuple(vecs′), eltypes′, i, itrs, state)
end
length(first(vecs)) == length(last(vecs)) ||
throw(ArgumentError("unzip called with uneven iterators"))
end
return Tuple(vecs)
end

# filter
Expand Down

0 comments on commit 4b839aa

Please sign in to comment.