Skip to content

Commit c820a50

Browse files
unzip: the inverse of zip
1 parent e0bdc76 commit c820a50

File tree

2 files changed

+66
-1
lines changed

2 files changed

+66
-1
lines changed

base/exports.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,7 @@ export
628628

629629
enumerate, # re-exported from Iterators
630630
zip,
631+
unzip,
631632
only,
632633

633634
# object identity and equality

base/iterators.jl

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import .Base:
2222
getindex, setindex!, get, iterate,
2323
popfirst!, isdone, peek
2424

25-
export enumerate, zip, rest, countfrom, take, drop, cycle, repeated, product, flatten, partition
25+
export enumerate, zip, unzip, rest, countfrom, take, drop,
26+
cycle, repeated, product, flatten, partition
2627

2728
tail_if_any(::Tuple{}) = ()
2829
tail_if_any(x::Tuple) = tail(x)
@@ -390,6 +391,69 @@ _zip_iterator_eltype(::Type{Tuple{}}) = HasEltype()
390391

391392
reverse(z::Zip) = Zip(map(reverse, z.is))
392393

394+
# unzip
395+
396+
"""
397+
unzip(itrs) -> Vector{<:Vector}
398+
399+
The `unzip` function takes an iterator of iterators and returns a vector of
400+
vectors such that the first vector contains the first element yielded by each
401+
iterator, the second vector the second element yielded by each iterator, etc.
402+
`unzip` is sort of an inverse to the `zip` operation, as the name suggests.
403+
In particular, if we define
404+
405+
≐(a, b) = collect(collect.(a)) == collect(collect.(b))
406+
407+
Then the following identities relating `zip` and `unzip` hold:
408+
409+
unzip(zip(itrs...)) ≐ itrs
410+
411+
zip(unzip(itrs)...) ≐ itrs
412+
413+
Note that `unzip` does not return an iterator: it always consumes all of
414+
its argument and all of each iterator yielded by its argument. It is only
415+
associated with iteration beacuse it is the inverse of `zip` which does
416+
yield an iterator.
417+
418+
# Examples
419+
420+
```jldoctest
421+
julia> unzip(enumerate("Hello"))
422+
2-element Array{Array{T,1} where T,1}:
423+
[1, 2, 3]
424+
['a', 'b', 'c']
425+
426+
julia> unzip([[1, 'a'], [2.5, 'z'], [0, 'x']])
427+
2-element Array{Array{T,1} where T,1}:
428+
Real[1, 2.5, 0]
429+
['a', 'z', 'x']
430+
```
431+
"""
432+
function unzip(itrs)
433+
n = Base.haslength(itrs) ? length(itrs) : -1
434+
vecs = Vector[]
435+
for itr in itrs
436+
for (j, x) in enumerate(itr)
437+
if length(vecs) < j
438+
v = [x]
439+
push!(vecs, v)
440+
n 0 && sizehint!(v, n)
441+
else
442+
v = vecs[j]
443+
if !(x isa eltype(v))
444+
T = Base.promote_typejoin(typeof(x), eltype(v))
445+
v = vecs[j] = copyto!(similar(v, T), v)
446+
n 0 && sizehint!(v, n)
447+
end
448+
push!(v, x)
449+
end
450+
end
451+
length(first(vecs)) == length(last(vecs)) ||
452+
throw(ArgumentError("unzip called with uneven iterators"))
453+
end
454+
return vecs
455+
end
456+
393457
# filter
394458

395459
struct Filter{F,I}

0 commit comments

Comments
 (0)