Skip to content

Commit

Permalink
fix doctest
Browse files Browse the repository at this point in the history
  • Loading branch information
N5N3 committed Oct 26, 2023
1 parent 7171bab commit b0d509b
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 119 deletions.
97 changes: 32 additions & 65 deletions docs/src/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,89 +6,56 @@ StructArrays support structures with custom data layout. The user is required to

Here is an example of a type `MyType` that has as custom fields either its field `data` or fields of its field `rest` (which is a named tuple):

```jldoctest advanced1
julia> using StructArrays
```@repl advanced1
using StructArrays
julia> struct MyType{T, NT<:NamedTuple}
data::T
rest::NT
end
struct MyType{T, NT<:NamedTuple}
data::T
rest::NT
end
julia> MyType(x; kwargs...) = MyType(x, values(kwargs))
MyType
MyType(x; kwargs...) = MyType(x, values(kwargs))
```

Let's create a small array of these objects:

```jldoctest advanced1
julia> s = [MyType(i/5, a=6-i, b=2) for i in 1:5]
5-element Vector{MyType{Float64, NamedTuple{(:a, :b), Tuple{Int64, Int64}}}}:
MyType{Float64, NamedTuple{(:a, :b), Tuple{Int64, Int64}}}(0.2, (a = 5, b = 2))
MyType{Float64, NamedTuple{(:a, :b), Tuple{Int64, Int64}}}(0.4, (a = 4, b = 2))
MyType{Float64, NamedTuple{(:a, :b), Tuple{Int64, Int64}}}(0.6, (a = 3, b = 2))
MyType{Float64, NamedTuple{(:a, :b), Tuple{Int64, Int64}}}(0.8, (a = 2, b = 2))
MyType{Float64, NamedTuple{(:a, :b), Tuple{Int64, Int64}}}(1.0, (a = 1, b = 2))
```@repl advanced1
s = [MyType(i/5, a=6-i, b=2) for i in 1:5]
```

The default `StructArray` does not unpack the `NamedTuple`:

```jldoctest advanced1
julia> sa = StructArray(s);
julia> sa.rest
5-element Vector{NamedTuple{(:a, :b), Tuple{Int64, Int64}}}:
(a = 5, b = 2)
(a = 4, b = 2)
(a = 3, b = 2)
(a = 2, b = 2)
(a = 1, b = 2)
julia> sa.a
ERROR: type NamedTuple has no field a
Stacktrace:
[1] component
[...]
```@repl advanced1
sa = StructArray(s);
sa.rest
sa.a
```

Suppose we wish to give the keywords their own fields. We can define custom `staticschema`, `component`, and `createinstance` methods for `MyType`:

```jldoctest advanced1
julia> function StructArrays.staticschema(::Type{MyType{T, NamedTuple{names, types}}}) where {T, names, types}
# Define the desired names and eltypes of the "fields"
return NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)}
end;
julia> function StructArrays.component(m::MyType, key::Symbol)
# Define a component-extractor
return key === :data ? getfield(m, 1) : getfield(getfield(m, 2), key)
end;
julia> function StructArrays.createinstance(::Type{MyType{T, NT}}, x, args...) where {T, NT}
# Generate an instance of MyType from components
return MyType(x, NT(args))
end;
```@repl advanced1
function StructArrays.staticschema(::Type{MyType{T, NamedTuple{names, types}}}) where {T, names, types}
# Define the desired names and eltypes of the "fields"
return NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)}
end;
function StructArrays.component(m::MyType, key::Symbol)
# Define a component-extractor
return key === :data ? getfield(m, 1) : getfield(getfield(m, 2), key)
end;
function StructArrays.createinstance(::Type{MyType{T, NT}}, x, args...) where {T, NT}
# Generate an instance of MyType from components
return MyType(x, NT(args))
end;
```

and now:

```jldoctest advanced1
julia> sa = StructArray(s);
julia> sa.a
5-element Vector{Int64}:
5
4
3
2
1
julia> sa.b
5-element Vector{Int64}:
2
2
2
2
2
```@repl advanced1
sa = StructArray(s);
sa.a
sa.b
```

The above strategy has been tested and implemented in [GeometryBasics.jl](https://github.com/JuliaGeometry/GeometryBasics.jl).
Expand Down
70 changes: 18 additions & 52 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,73 +9,39 @@ The package was largely inspired by the `Columns` type in [IndexedTables](https:
## Collection and initialization

One can create a `StructArray` by providing the struct type and a tuple or NamedTuple of field arrays:
```jldoctest intro
julia> using StructArrays
julia> struct Foo{T}
a::T
b::T
end
julia> adata = [1 2; 3 4]; bdata = [10 20; 30 40];
julia> x = StructArray{Foo}((adata, bdata))
2×2 StructArray(::Matrix{Int64}, ::Matrix{Int64}) with eltype Foo:
Foo{Int64}(1, 10) Foo{Int64}(2, 20)
Foo{Int64}(3, 30) Foo{Int64}(4, 40)
```@repl intro
using StructArrays
struct Foo{T}
a::T
b::T
end
adata = [1 2; 3 4]; bdata = [10 20; 30 40];
x = StructArray{Foo}((adata, bdata))
```

You can also initialze a StructArray by passing in a NamedTuple, in which case the name (rather than the order) specifies how the input arrays are assigned to fields:

```jldoctest intro
julia> x = StructArray{Foo}((b = adata, a = bdata)) # initialize a with bdata and vice versa
2×2 StructArray(::Matrix{Int64}, ::Matrix{Int64}) with eltype Foo:
Foo{Int64}(10, 1) Foo{Int64}(20, 2)
Foo{Int64}(30, 3) Foo{Int64}(40, 4)
```@repl intro
x = StructArray{Foo}((b = adata, a = bdata)) # initialize a with bdata and vice versa
```

If a struct is not specified, a StructArray with Tuple or NamedTuple elements will be created:
```jldoctest intro
julia> x = StructArray((adata, bdata))
2×2 StructArray(::Matrix{Int64}, ::Matrix{Int64}) with eltype Tuple{Int64, Int64}:
(1, 10) (2, 20)
(3, 30) (4, 40)
julia> x = StructArray((a = adata, b = bdata))
2×2 StructArray(::Matrix{Int64}, ::Matrix{Int64}) with eltype NamedTuple{(:a, :b), Tuple{Int64, Int64}}:
(a = 1, b = 10) (a = 2, b = 20)
(a = 3, b = 30) (a = 4, b = 40)
```@repl intro
x = StructArray((adata, bdata))
x = StructArray((a = adata, b = bdata))
```

It's also possible to create a `StructArray` by choosing a particular dimension to interpret as the components of a struct:

```jldoctest intro
julia> x = StructArray{Complex{Int}}(adata; dims=1) # along dimension 1, the first item `re` and the second is `im`
2-element StructArray(view(::Matrix{Int64}, 1, :), view(::Matrix{Int64}, 2, :)) with eltype Complex{Int64}:
1 + 3im
2 + 4im
julia> x = StructArray{Complex{Int}}(adata; dims=2) # along dimension 2, the first item `re` and the second is `im`
2-element StructArray(view(::Matrix{Int64}, :, 1), view(::Matrix{Int64}, :, 2)) with eltype Complex{Int64}:
1 + 2im
3 + 4im
```@repl intro
x = StructArray{Complex{Int}}(adata; dims=1) # along dimension 1, the first item `re` and the second is `im`
x = StructArray{Complex{Int}}(adata; dims=2) # along dimension 2, the first item `re` and the second is `im`
```

One can also create a `StructArray` from an iterable of structs without creating an intermediate `Array`:

```jldoctest intro
julia> StructArray(log(j+2.0*im) for j in 1:10)
10-element StructArray(::Vector{Float64}, ::Vector{Float64}) with eltype ComplexF64:
0.8047189562170501 + 1.1071487177940904im
1.0397207708399179 + 0.7853981633974483im
1.2824746787307684 + 0.5880026035475675im
1.4978661367769954 + 0.4636476090008061im
1.683647914993237 + 0.3805063771123649im
1.8444397270569681 + 0.3217505543966422im
1.985145956776061 + 0.27829965900511133im
2.1097538525880535 + 0.24497866312686414im
2.2213256282451583 + 0.21866894587394195im
2.3221954495706862 + 0.19739555984988078im
```@repl intro
StructArray(log(j+2.0*im) for j in 1:10)
```

Another option is to create an uninitialized `StructArray` and then fill it with data. Just like in normal arrays, this is done with the `undef` syntax:
Expand Down
4 changes: 2 additions & 2 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ julia> s_pooled = StructArrays.replace_storage(s) do v
isbitstype(eltype(v)) ? v : convert(PooledArray, v)
end
$(if VERSION < v"1.6-"
"3-element StructArray(::UnitRange{Int64}, ::PooledArray{String,UInt32,1,Array{UInt32,1}}) with eltype NamedTuple{(:a, :b),Tuple{Int64,String}}:"
"3-element StructArray(::UnitRange{Int64}, ::PooledArray{String,UInt32,1,Array{UInt32,1}}) with eltype $(NamedTuple{(:a, :b),Tuple{Int64,String}}):"
else
"3-element StructArray(::UnitRange{Int64}, ::PooledVector{String, UInt32, Vector{UInt32}}) with eltype NamedTuple{(:a, :b), Tuple{Int64, String}}:"
"3-element StructArray(::UnitRange{Int64}, ::PooledVector{String, UInt32, Vector{UInt32}}) with eltype $(NamedTuple{(:a, :b), Tuple{Int64, String}}):"
end)
(a = 1, b = "string")
(a = 2, b = "string")
Expand Down

0 comments on commit b0d509b

Please sign in to comment.