Last active
September 20, 2018 07:56
MWE for collecting using a functional style
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# define an iterator with unknown type and length | |
struct MyItr N::Int end | |
Base.IteratorSize(::Type{MyItr}) = Base.SizeUnknown() | |
Base.IteratorEltype(::Type{MyItr}) = Base.EltypeUnknown() | |
function Base.iterate(itr::MyItr, state = 1) | |
if state > itr.N | |
nothing | |
else | |
val = state == 200 ? missing : state | |
(val, state + 1) | |
end | |
end | |
# "functional" implementation | |
store(collection::Vector{T}, elt::S) where {T, S <: T} = | |
(push!(collection, elt); (collection, false)) | |
store(collection, elt) = (vcat(collection, elt), true) | |
function mycollect_fun(itr) | |
y = iterate(itr) | |
y ≡ nothing && error("not allowed") | |
elt, state = y | |
_mycollect_fun([elt], itr, state) | |
end | |
function _mycollect_fun(collection, itr, state) | |
while true | |
y = iterate(itr, state) | |
y ≡ nothing && return collection | |
elt, state = y | |
collection, changed = store(collection, elt) | |
changed && return _mycollect_fun(collection, itr, state) | |
end | |
end | |
# "stateful" implementation | |
canstore(collection::Vector{T}, elt::S) where {T, S <: T} = true | |
canstore(collection, elt) = false | |
store!(collection::Vector{T}, elt::S) where {T, S <: T} = push!(collection, elt) | |
function expand(collection::Vector{T}, elt::S) where {T,S} | |
U = Base.promote_typejoin(T, S) | |
newcollection = Vector{U}(undef, length(collection)) | |
copyto!(newcollection, collection) | |
push!(newcollection, elt) | |
newcollection | |
end | |
function mycollect_mut(itr) | |
y = iterate(itr) | |
y ≡ nothing && error("not allowed") | |
elt, state = y | |
_mycollect_mut([elt], itr, state) | |
end | |
function _mycollect_mut(collection, itr, state) | |
while true | |
y = iterate(itr, state) | |
y ≡ nothing && return collection | |
elt, state = y | |
!canstore(collection, elt) && return _mycollect_mut(expand(collection, elt), itr, state) | |
store!(collection, elt) | |
end | |
end | |
# "functional" implementation take 2 | |
store!_or_widen(collection::Vector{T}, elt::S) where {T, S <: T} = push!(collection, elt) | |
store!_or_widen(collection, elt) = vcat(collection, elt) | |
function mycollect_funeq(itr) | |
y = iterate(itr) | |
y ≡ nothing && error("not allowed") | |
elt, state = y | |
_mycollect_funeq([elt], itr, state) | |
end | |
function _mycollect_funeq(collection, itr, state) | |
while true | |
y = iterate(itr, state) | |
y ≡ nothing && return collection | |
elt, state = y | |
expanded = store!_or_widen(collection, elt) | |
expanded ≡ collection || return _mycollect_funeq(expanded, itr, state) | |
end | |
end | |
using BenchmarkTools | |
itr = MyItr(1000) | |
@btime collect($itr); | |
@btime mycollect_fun($itr); | |
@btime mycollect_mut($itr); | |
@btime mycollect_funeq($itr); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment