diff --git a/docs/src/index.md b/docs/src/index.md index 434c30c..36d064c 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -156,3 +156,11 @@ Iterate over struct or named tuple property values. ```@docs propertyvalues ``` + +## fieldvalues(x) + +Like `(getfield(x, i) for i in 1:nfields(x))` but faster. + +```@docs +fieldvalues +``` diff --git a/src/IterTools.jl b/src/IterTools.jl index 478f3c5..5b6b468 100644 --- a/src/IterTools.jl +++ b/src/IterTools.jl @@ -28,7 +28,8 @@ export flagfirst, takewhile, properties, - propertyvalues + propertyvalues, + fieldvalues function has_length(it) it_size = IteratorSize(it) @@ -910,6 +911,8 @@ Base.IteratorSize(it::TakeWhile) = Base.SizeUnknown() eltype(::Type{TakeWhile{I}}) where {I} = eltype(I) IteratorEltype(::Type{TakeWhile{I}}) where {I} = IteratorEltype(I) +# Properties + struct Properties{T} x::T n::Int @@ -940,6 +943,8 @@ function iterate(p::Properties, state=1) return ((name, getproperty(p.x, name)), state + 1) end +# PropertyValues + struct PropertyValues{T} x::T n::Int @@ -958,6 +963,7 @@ julia> collect(propertyvalues(1 + 2im)) 2 ``` """ + function propertyvalues(x::T) where T names = propertynames(x) return PropertyValues{T}(x, length(names), names) @@ -973,4 +979,32 @@ end length(p::Union{Properties, PropertyValues}) = p.n IteratorSize(::Type{<:Union{Properties, PropertyValues}}) = HasLength() +# FieldValues + +struct FieldValues{T} + x::T +end + +""" + fieldvalues(x) + +Iterate through the values of the fields of `x`. + +```jldoctest +julia> collect(fieldvalues(1 + 2im)) +2-element Array{Any,1}: + 1 + 2 +``` +""" +fieldvalues(x::T) where {T} = FieldValues{T}(x) +length(fs::FieldValues{T}) where {T} = fieldcount(T) +IteratorSize(::Type{<:FieldValues}) = HasLength() + +function iterate(fs::FieldValues, state=1) + state > length(fs) && return nothing + + return (getfield(fs.x, state), state + 1) +end + end # module IterTools diff --git a/test/runtests.jl b/test/runtests.jl index 3ce8d9a..383fec0 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -455,5 +455,22 @@ include("testing_macros.jl") pv3 = propertyvalues(HasLength()) @test collect(pv3) == Any[] end + + @testset "fieldvalues" begin + fv1 = fieldvalues(1 + 2im) + @test IteratorEltype(fv1) isa HasEltype + @test eltype(fv1) == Any + @test IteratorSize(fv1) isa HasLength + @test length(fv1) == 2 + @test collect(fv1) == Any[1, 2] + + tp = ("", 1, 2.0) + fv2 = fieldvalues(tp) + @test collect(fv2) == collect(tp) + + # HasLength used as an example no-field struct + fv3 = fieldvalues(HasLength()) + @test collect(fv3) == Any[] + end end end