Skip to content

Commit 1f8b442

Browse files
authored
Add Iterators.map (#34352)
1 parent e96728c commit 1f8b442

File tree

4 files changed

+39
-9
lines changed

4 files changed

+39
-9
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ New library functions
3636

3737
* New function `Base.kron!` and corresponding overloads for various matrix types for performing Kronecker product in-place. ([#31069]).
3838
* New function `Base.Threads.foreach(f, channel::Channel)` for multithreaded `Channel` consumption. ([#34543]).
39+
* `Iterators.map` is added. It provides another syntax `Iterators.map(f, iterators...)`
40+
for writing `(f(args...) for args in zip(iterators...))`, i.e. a lazy `map` ([#34352]).
3941

4042
New library features
4143
--------------------

base/iterators.jl

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ using .Base:
1212
@inline, Pair, AbstractDict, IndexLinear, IndexCartesian, IndexStyle, AbstractVector, Vector,
1313
tail, tuple_type_head, tuple_type_tail, tuple_type_cons, SizeUnknown, HasLength, HasShape,
1414
IsInfinite, EltypeUnknown, HasEltype, OneTo, @propagate_inbounds, Generator, AbstractRange,
15-
LinearIndices, (:), |, +, -, !==, !, <=, <, missing, map, any, @boundscheck, @inbounds
15+
LinearIndices, (:), |, +, -, !==, !, <=, <, missing, any, @boundscheck, @inbounds
1616

1717
import .Base:
1818
first, last,
@@ -24,6 +24,26 @@ import .Base:
2424

2525
export enumerate, zip, rest, countfrom, take, drop, takewhile, dropwhile, cycle, repeated, product, flatten, partition
2626

27+
"""
28+
Iterators.map(f, iterators...)
29+
30+
Create a lazy mapping. This is another syntax for writing
31+
`(f(args...) for args in zip(iterators...))`.
32+
33+
!!! compat "Julia 1.6"
34+
This function requires at least Julia 1.6.
35+
36+
# Examples
37+
```jldoctest
38+
julia> collect(Iterators.map(x -> x^2, 1:3))
39+
3-element Array{Int64,1}:
40+
1
41+
4
42+
9
43+
```
44+
"""
45+
map(f, args...) = Base.Generator(f, args...)
46+
2747
tail_if_any(::Tuple{}) = ()
2848
tail_if_any(x::Tuple) = tail(x)
2949

@@ -322,17 +342,17 @@ eltype(::Type{Zip{Is}}) where {Is<:Tuple} = _zip_eltype(Is)
322342
_zip_eltype(::Type{Is}) where {Is<:Tuple} =
323343
tuple_type_cons(eltype(tuple_type_head(Is)), _zip_eltype(tuple_type_tail(Is)))
324344
_zip_eltype(::Type{Tuple{}}) = Tuple{}
325-
@inline isdone(z::Zip) = _zip_any_isdone(z.is, map(_ -> (), z.is))
326-
@inline isdone(z::Zip, ss) = _zip_any_isdone(z.is, map(tuple, ss))
345+
@inline isdone(z::Zip) = _zip_any_isdone(z.is, Base.map(_ -> (), z.is))
346+
@inline isdone(z::Zip, ss) = _zip_any_isdone(z.is, Base.map(tuple, ss))
327347
@inline function _zip_any_isdone(is, ss)
328348
d1 = isdone(is[1], ss[1]...)
329349
d1 === true && return true
330350
return d1 | _zip_any_isdone(tail(is), tail(ss))
331351
end
332352
@inline _zip_any_isdone(::Tuple{}, ::Tuple{}) = false
333353

334-
@propagate_inbounds iterate(z::Zip) = _zip_iterate_all(z.is, map(_ -> (), z.is))
335-
@propagate_inbounds iterate(z::Zip, ss) = _zip_iterate_all(z.is, map(tuple, ss))
354+
@propagate_inbounds iterate(z::Zip) = _zip_iterate_all(z.is, Base.map(_ -> (), z.is))
355+
@propagate_inbounds iterate(z::Zip, ss) = _zip_iterate_all(z.is, Base.map(tuple, ss))
336356

337357
# This first queries isdone from every iterator. If any gives true, it immediately returns
338358
# 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} =
388408
_zip_iterator_eltype(tuple_type_tail(Is)))
389409
_zip_iterator_eltype(::Type{Tuple{}}) = HasEltype()
390410

391-
reverse(z::Zip) = Zip(map(reverse, z.is))
411+
reverse(z::Zip) = Zip(Base.map(reverse, z.is))
392412

393413
# filter
394414

@@ -982,7 +1002,7 @@ end
9821002
isdone(P) === true && return nothing
9831003
next = _piterate(P.iterators...)
9841004
next === nothing && return nothing
985-
return (map(x -> x[1], next), next)
1005+
return (Base.map(x -> x[1], next), next)
9861006
end
9871007

9881008
@inline _piterate1(::Tuple{}, ::Tuple{}) = nothing
@@ -1003,10 +1023,10 @@ end
10031023
isdone(P, states) === true && return nothing
10041024
next = _piterate1(P.iterators, states)
10051025
next === nothing && return nothing
1006-
return (map(x -> x[1], next), next)
1026+
return (Base.map(x -> x[1], next), next)
10071027
end
10081028

1009-
reverse(p::ProductIterator) = ProductIterator(map(reverse, p.iterators))
1029+
reverse(p::ProductIterator) = ProductIterator(Base.map(reverse, p.iterators))
10101030

10111031
# flatten an iterator of iterators
10121032

doc/src/base/iterators.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Base.Iterators.repeated
1515
Base.Iterators.product
1616
Base.Iterators.flatten
1717
Base.Iterators.partition
18+
Base.Iterators.map
1819
Base.Iterators.filter
1920
Base.Iterators.accumulate
2021
Base.Iterators.reverse

test/iterators.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@ end
101101
@test length(zip(1:3,product(1:7,cycle(1:3)))) == 3
102102
@test length(zip(1:3,product(1:7,cycle(1:3)),8)) == 1
103103

104+
# map
105+
# ----
106+
@testset "Iterators.map" begin
107+
@test collect(Iterators.map(string, 1:3)::Base.Generator) == map(string, 1:3)
108+
@test collect(Iterators.map(tuple, 1:3, 4:6)::Base.Generator) == map(tuple, 1:3, 4:6)
109+
end
110+
104111
# rest
105112
# ----
106113
let s = "hello"

0 commit comments

Comments
 (0)