Skip to content

Commit 7bc3742

Browse files
authored
add Iterators.accumulate (#34033)
1 parent 22bb426 commit 7bc3742

File tree

4 files changed

+67
-0
lines changed

4 files changed

+67
-0
lines changed

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ New library functions
3636
* `readdir` output is now guaranteed to be sorted. The `sort` keyword allows opting out of sorting to get names in OS-native order ([#33542]).
3737
* The new `only(x)` function returns the one-and-only element of a collection `x`, and throws an `ArgumentError` if `x` contains zero or multiple elements. ([#33129])
3838
* `takewhile` and `dropwhile` have been added to the Iterators submodule ([#33437]).
39+
* `accumulate` has been added to the Iterators submodule.
3940
* `filter` can now act on a `Tuple` ([#32968]).
4041
* There is a now an `evalpoly` (generated) function meant to take the role of the `@evalpoly` macro. The function is just as efficient as the macro while giving added flexibility, so it should be preferred over `@evalpoly`. `evalpoly` takes a list of coefficients as a tuple, so where one might write `@evalpoly(x, p1, p2, p3)` one would instead write `evalpoly(x, (p1, p2, p3))`.
4142

base/iterators.jl

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,59 @@ IteratorSize(::Type{<:Filter}) = SizeUnknown()
442442

443443
reverse(f::Filter) = Filter(f.flt, reverse(f.itr))
444444

445+
# Accumulate -- partial reductions of a function over an iterator
446+
447+
struct Accumulate{F,I}
448+
f::F
449+
itr::I
450+
end
451+
452+
"""
453+
Iterators.accumulate(f, itr)
454+
455+
Given a 2-argument function `f` and an iterator `itr`, return a new
456+
iterator that successively applies `f` to the previous value and the
457+
next element of `itr`.
458+
459+
This is effectively a lazy version of [`Base.accumulate`](@ref).
460+
461+
# Examples
462+
```jldoctest
463+
julia> f = Iterators.accumulate(+, [1,2,3,4])
464+
Base.Iterators.Accumulate{typeof(+),Array{Int64,1}}(+, [1, 2, 3, 4])
465+
466+
julia> foreach(println, f)
467+
1
468+
3
469+
6
470+
10
471+
```
472+
"""
473+
accumulate(f, itr) = Accumulate(f, itr)
474+
475+
function iterate(itr::Accumulate)
476+
state = iterate(itr.itr)
477+
if state === nothing
478+
return nothing
479+
end
480+
return (state[1], state)
481+
end
482+
483+
function iterate(itr::Accumulate, state)
484+
nxt = iterate(itr.itr, state[2])
485+
if nxt === nothing
486+
return nothing
487+
end
488+
val = itr.f(state[1], nxt[1])
489+
return (val, (val, nxt[2]))
490+
end
491+
492+
length(itr::Accumulate) = length(itr.itr)
493+
size(itr::Accumulate) = size(itr.itr)
494+
495+
IteratorSize(::Type{Accumulate{F,I}}) where {F,I} = IteratorSize(I)
496+
IteratorEltype(::Type{<:Accumulate}) = EltypeUnknown()
497+
445498
# Rest -- iterate starting at the given state
446499

447500
struct Rest{I,S}

doc/src/base/iterators.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Base.Iterators.product
1414
Base.Iterators.flatten
1515
Base.Iterators.partition
1616
Base.Iterators.filter
17+
Base.Iterators.accumulate
1718
Base.Iterators.reverse
1819
Base.Iterators.only
1920
Base.Iterators.peel

test/iterators.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,3 +784,15 @@ end
784784
@testset "flatten empty tuple" begin
785785
@test isempty(collect(Iterators.flatten(())))
786786
end
787+
788+
@testset "Iterators.accumulate" begin
789+
@test collect(Iterators.accumulate(+, [])) == []
790+
@test collect(Iterators.accumulate(+, [1])) == [1]
791+
@test collect(Iterators.accumulate(+, [1,2])) == [1,3]
792+
@test collect(Iterators.accumulate(+, [1,2,3])) == [1,3,6]
793+
@test collect(Iterators.accumulate(=>, [:a,:b,:c])) == [:a, :a => :b, (:a => :b) => :c]
794+
@test length(Iterators.accumulate(+, [10,20,30])) == 3
795+
@test size(Iterators.accumulate(max, rand(2,3))) == (2,3)
796+
@test Base.IteratorSize(Iterators.accumulate(max, rand(2,3))) === Base.IteratorSize(rand(2,3))
797+
@test Base.IteratorEltype(Iterators.accumulate(*, ())) isa Base.EltypeUnknown
798+
end

0 commit comments

Comments
 (0)