Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unzip #33324

Closed
wants to merge 6 commits into from
Closed

Add unzip #33324

wants to merge 6 commits into from

Conversation

bramtayl
Copy link
Contributor

I finally switched to Ubuntu, and suddenly building and testing Base became much more manageable! I think this should be pretty close to good.

Closes #13942

base/array.jl Outdated Show resolved Hide resolved
base/array.jl Outdated Show resolved Hide resolved
base/array.jl Outdated Show resolved Hide resolved
@bramtayl
Copy link
Contributor Author

CI failures unrelated, correct?

base/array.jl Outdated Show resolved Hide resolved
@bramtayl
Copy link
Contributor Author

CI failures unrelated

@bramtayl
Copy link
Contributor Author

@StefanKarpinski can you assign someone to review this?

@StefanKarpinski
Copy link
Sponsor Member

It feels like a lot of stuff to implement unzip. Here's a version that I cooked up:

"""
    unzip(itrs) -> Vector{<:Vector}

The `unzip` function takes an iterator of iterators and returns a vector of
vectors such that `zip(unzip(itrs)...) == map(itr->tuple(itr...), itrs)`.

# Examples

    julia> unzip(enumerate("Hello"))
    2-element Array{Array{T,1} where T,1}:
     [1, 2, 3]
     ['a', 'b', 'c']

    julia> unzip([[1, 'a'], [2.5, 'z'], [0, 'x']])
    2-element Array{Array{T,1} where T,1}:
     Real[1, 2.5, 0]
     ['a', 'z', 'x']

"""
function unzip(itrs)
    outer = iterate(itrs)
    outer === nothing && return []
    vals, state = outer
    vecs = Vector[[val] for val in vals]
    local n
    if Base.haslength(itrs)
        n = length(itrs)
        for vec in vecs
            sizehint!(vec, n)
        end
    end
    while true
        outer = iterate(itrs, state)
        outer === nothing && return vecs
        vals, state = outer
        for (j, val) = enumerate(vals)
            vec = vecs[j]
            if !(val isa eltype(vec))
                T = Base.promote_typejoin(typeof(val), eltype(vec))
                vec = vecs[j] = copyto!(similar(vec, T), vec)
                @isdefined(n) && sizehint!(vec, n)
            end
            push!(vec, val)
        end
    end
end

@StefanKarpinski
Copy link
Sponsor Member

I guess the question is what one wants unzip to do. Here's a simpler version that allows unzipping unevenly sized arrays—which is of questionable desirability—but makes it simpler to implement:

function unzip(itrs; uneven::Bool=false)
    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)
                end
                push!(v, x)
            end
        end
        uneven || length(first(vecs)) == length(last(vecs)) ||
            throw(ArgumentError("unzip called with uneven iterators"))
    end
    return vecs
end

Works the same on evenly sized arrays but here's an example with unevenly sized ones:

julia> unzip([[1, 'a'], [2.5, 'z', "extra"], [0, 'x']], uneven=true)
3-element Array{Array{T,1} where T,1}:
 Real[1, 2.5, 0]
 ['a', 'z', 'x']
 ["extra"]

This just goes through each iterable thing and collects into the vector at the corresponding index.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Base.unzip()
4 participants