From d08b151288e4e6f56e93302b43292cfb2bb233eb Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 11 Jan 2020 17:09:36 -0800 Subject: [PATCH 1/9] Add Iterators.map --- base/iterators.jl | 44 ++++++++++++++++++++++++++++----------- doc/src/base/iterators.md | 1 + test/iterators.jl | 7 +++++++ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/base/iterators.jl b/base/iterators.jl index 7f8525d8e1d82..5dca066bd25ca 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -12,7 +12,7 @@ using .Base: @inline, Pair, AbstractDict, IndexLinear, IndexCartesian, IndexStyle, AbstractVector, Vector, tail, tuple_type_head, tuple_type_tail, tuple_type_cons, SizeUnknown, HasLength, HasShape, IsInfinite, EltypeUnknown, HasEltype, OneTo, @propagate_inbounds, Generator, AbstractRange, - LinearIndices, (:), |, +, -, !==, !, <=, <, missing, map, any, @boundscheck, @inbounds + LinearIndices, (:), |, +, -, !==, !, <=, <, missing, any, @boundscheck, @inbounds import .Base: first, last, @@ -22,7 +22,27 @@ import .Base: getindex, setindex!, get, iterate, popfirst!, isdone, peek -export enumerate, zip, rest, countfrom, take, drop, takewhile, dropwhile, cycle, repeated, product, flatten, partition +export enumerate, zip, rest, countfrom, take, drop, takewhile, dropwhile, cycle, repeated, product, flatten, partition, map + +""" + Iterators.map(f, iterators...) + +Create a lazy mapping. This is another syntax for writing +`(f(args...) for args in zip(iterators...))`. + +!!! compat "Julia 1.5" + This function requires at least Julia 1.5. + +# Examples +```jldoctest +julia> collect(Iterators.map(x -> x^2, 1:3)) +3-element Array{Int64,1}: + 1 + 4 + 9 +``` +""" +map(f, args...) = Base.Generator(f, args...) tail_if_any(::Tuple{}) = () tail_if_any(x::Tuple) = tail(x) @@ -314,16 +334,16 @@ function _zip_min_length(is) end end _zip_min_length(is::Tuple{}) = nothing -size(z::Zip) = _promote_shape(map(size, z.is)...) -axes(z::Zip) = _promote_shape(map(axes, z.is)...) +size(z::Zip) = _promote_shape(Base.map(size, z.is)...) +axes(z::Zip) = _promote_shape(Base.map(axes, z.is)...) _promote_shape(a, b...) = promote_shape(a, _promote_shape(b...)) _promote_shape(a) = a eltype(::Type{Zip{Is}}) where {Is<:Tuple} = _zip_eltype(Is) _zip_eltype(::Type{Is}) where {Is<:Tuple} = tuple_type_cons(eltype(tuple_type_head(Is)), _zip_eltype(tuple_type_tail(Is))) _zip_eltype(::Type{Tuple{}}) = Tuple{} -@inline isdone(z::Zip) = _zip_any_isdone(z.is, map(_ -> (), z.is)) -@inline isdone(z::Zip, ss) = _zip_any_isdone(z.is, map(tuple, ss)) +@inline isdone(z::Zip) = _zip_any_isdone(z.is, Base.map(_ -> (), z.is)) +@inline isdone(z::Zip, ss) = _zip_any_isdone(z.is, Base.map(tuple, ss)) @inline function _zip_any_isdone(is, ss) d1 = isdone(is[1], ss[1]...) d1 === true && return true @@ -331,8 +351,8 @@ _zip_eltype(::Type{Tuple{}}) = Tuple{} end @inline _zip_any_isdone(::Tuple{}, ::Tuple{}) = false -@propagate_inbounds iterate(z::Zip) = _zip_iterate_all(z.is, map(_ -> (), z.is)) -@propagate_inbounds iterate(z::Zip, ss) = _zip_iterate_all(z.is, map(tuple, ss)) +@propagate_inbounds iterate(z::Zip) = _zip_iterate_all(z.is, Base.map(_ -> (), z.is)) +@propagate_inbounds iterate(z::Zip, ss) = _zip_iterate_all(z.is, Base.map(tuple, ss)) # This first queries isdone from every iterator. If any gives true, it immediately returns # nothing. It then iterates all those where isdone returned missing, afterwards all those @@ -388,7 +408,7 @@ _zip_iterator_eltype(::Type{Is}) where {Is<:Tuple} = _zip_iterator_eltype(tuple_type_tail(Is))) _zip_iterator_eltype(::Type{Tuple{}}) = HasEltype() -reverse(z::Zip) = Zip(map(reverse, z.is)) +reverse(z::Zip) = Zip(Base.map(reverse, z.is)) # filter @@ -971,7 +991,7 @@ end isdone(P) === true && return nothing next = _piterate(P.iterators...) next === nothing && return nothing - return (map(x -> x[1], next), next) + return (Base.map(x -> x[1], next), next) end @inline _piterate1(::Tuple{}, ::Tuple{}) = nothing @@ -992,10 +1012,10 @@ end isdone(P, states) === true && return nothing next = _piterate1(P.iterators, states) next === nothing && return nothing - return (map(x -> x[1], next), next) + return (Base.map(x -> x[1], next), next) end -reverse(p::ProductIterator) = ProductIterator(map(reverse, p.iterators)) +reverse(p::ProductIterator) = ProductIterator(Base.map(reverse, p.iterators)) # flatten an iterator of iterators diff --git a/doc/src/base/iterators.md b/doc/src/base/iterators.md index debfb6f4d3b16..5375a60180240 100644 --- a/doc/src/base/iterators.md +++ b/doc/src/base/iterators.md @@ -13,6 +13,7 @@ Base.Iterators.repeated Base.Iterators.product Base.Iterators.flatten Base.Iterators.partition +Base.Iterators.map Base.Iterators.filter Base.Iterators.accumulate Base.Iterators.reverse diff --git a/test/iterators.jl b/test/iterators.jl index 71d4e2b74cb67..8df943d114bce 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -65,6 +65,13 @@ end @test length(zip(1:3,product(1:7,cycle(1:3)))) == 3 @test length(zip(1:3,product(1:7,cycle(1:3)),8)) == 1 +# map +# ---- +@testset "Iterators.map" begin + @test collect(Iterators.map(string, 1:3)::Base.Generator) == map(string, 1:3) + @test collect(Iterators.map(tuple, 1:3, 4:6)::Base.Generator) == map(tuple, 1:3, 4:6) +end + # rest # ---- let s = "hello" From 3f0652f9070542b436fcf5b752a81d470d8de189 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 11 Jan 2020 17:18:00 -0800 Subject: [PATCH 2/9] Mention Iterators.map in NEWS.md --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 90266f006a6d8..12c6f2684228c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -19,7 +19,7 @@ Build system changes New library functions --------------------- - +* `Iterators.map` is added ([#34352]). New library features -------------------- From ff8734a16aee5cac66feafd4c8ea7cf21fbe1a38 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 11 Jan 2020 18:51:45 -0800 Subject: [PATCH 3/9] Fix test/iterators.jl --- test/iterators.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/iterators.jl b/test/iterators.jl index 8df943d114bce..12815362c4b0e 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -3,6 +3,8 @@ using Base.Iterators using Random +using Base: map + # zip and filter iterators # issue #4718 @test collect(Iterators.filter(x->x[1], zip([true, false, true, false],"abcd"))) == [(true,'a'),(true,'c')] From e8f14a31ef3990e258eeda4e84b230bafc48dacd Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Mon, 13 Jan 2020 14:43:34 -0800 Subject: [PATCH 4/9] Unexport Iterators.map --- base/iterators.jl | 2 +- test/iterators.jl | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/base/iterators.jl b/base/iterators.jl index 5dca066bd25ca..bc8479ab777cd 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -22,7 +22,7 @@ import .Base: getindex, setindex!, get, iterate, popfirst!, isdone, peek -export enumerate, zip, rest, countfrom, take, drop, takewhile, dropwhile, cycle, repeated, product, flatten, partition, map +export enumerate, zip, rest, countfrom, take, drop, takewhile, dropwhile, cycle, repeated, product, flatten, partition """ Iterators.map(f, iterators...) diff --git a/test/iterators.jl b/test/iterators.jl index 12815362c4b0e..8df943d114bce 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -3,8 +3,6 @@ using Base.Iterators using Random -using Base: map - # zip and filter iterators # issue #4718 @test collect(Iterators.filter(x->x[1], zip([true, false, true, false],"abcd"))) == [(true,'a'),(true,'c')] From 4f1e0920877732b40585756e2b0cee28d1392786 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Mon, 13 Jan 2020 14:47:08 -0800 Subject: [PATCH 5/9] Explain what Iterators.map does in NEWS.md --- NEWS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 12c6f2684228c..0aabd7aa1179f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -19,7 +19,8 @@ Build system changes New library functions --------------------- -* `Iterators.map` is added ([#34352]). +* `Iterators.map` is added. It provides another syntax `Iterators.map(f, iterators...)` + for wiring `(f(args...) for args in zip(iterators...))` ([#34352]). New library features -------------------- From cf60cf290ac3cdbb1c40e5d1a6169075bb3e24e7 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Tue, 14 Jan 2020 14:07:44 -0800 Subject: [PATCH 6/9] Update NEWS.md Co-Authored-By: Stefan Karpinski --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 0aabd7aa1179f..51067978e6477 100644 --- a/NEWS.md +++ b/NEWS.md @@ -20,7 +20,7 @@ Build system changes New library functions --------------------- * `Iterators.map` is added. It provides another syntax `Iterators.map(f, iterators...)` - for wiring `(f(args...) for args in zip(iterators...))` ([#34352]). + for writing `(f(args...) for args in zip(iterators...))`, i.e. a lazy `map` ([#34352]). New library features -------------------- From b04cf4579dac7a95ba6512967e6444b70890896f Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 6 Jun 2020 17:14:41 -0700 Subject: [PATCH 7/9] Remove NEWS item --- NEWS.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index aa96f542c5e6b..bf73c1fb82a73 100644 --- a/NEWS.md +++ b/NEWS.md @@ -106,8 +106,6 @@ Build system changes New library functions --------------------- * The `@ccall` macro has been added to Base. It is a near drop-in replacement for `ccall` with more Julia-like syntax. It also wraps the new `foreigncall` API for varargs of different types, though it lacks the capability to specify an LLVM calling convention. ([#32748]) -* `Iterators.map` is added. It provides another syntax `Iterators.map(f, iterators...)` - for writing `(f(args...) for args in zip(iterators...))`, i.e. a lazy `map` ([#34352]). * New functions `mergewith` and `mergewith!` supersede `merge` and `merge!` with `combine` argument. They don't have the restriction for `combine` to be a `Function` and also provide one-argument method that returns a closure. The old methods of `merge` and From 9d900d0b9f67fb93d1ac5a8e0d3448d4e4164fee Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 6 Jun 2020 17:15:18 -0700 Subject: [PATCH 8/9] Add NEWS back --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 71a2d66d7946c..38aea956d9fb0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -35,6 +35,8 @@ New library functions * New function `Base.kron!` and corresponding overloads for various matrix types for performing Kronecker product in-place. ([#31069]). * New function `Base.Threads.foreach(f, channel::Channel)` for multithreaded `Channel` consumption. ([#34543]). +* `Iterators.map` is added. It provides another syntax `Iterators.map(f, iterators...)` + for writing `(f(args...) for args in zip(iterators...))`, i.e. a lazy `map` ([#34352]). New library features -------------------- From 775733637d6783205e1621683c05355c5ec134e6 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 6 Jun 2020 17:16:59 -0700 Subject: [PATCH 9/9] Fix compat --- base/iterators.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/iterators.jl b/base/iterators.jl index 826e88e9b55bd..fe5146f7585ab 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -30,8 +30,8 @@ export enumerate, zip, rest, countfrom, take, drop, takewhile, dropwhile, cycle, Create a lazy mapping. This is another syntax for writing `(f(args...) for args in zip(iterators...))`. -!!! compat "Julia 1.5" - This function requires at least Julia 1.5. +!!! compat "Julia 1.6" + This function requires at least Julia 1.6. # Examples ```jldoctest