Skip to content

Commit 75a3e91

Browse files
author
Pietro Vertechi
authored
Constructor reorg (#37)
1 parent 522ef2a commit 75a3e91

File tree

4 files changed

+52
-39
lines changed

4 files changed

+52
-39
lines changed

src/sort.jl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,11 @@ function finduniquesorted(args...)
5555
(row => p[idxs] for (row, idxs) in t)
5656
end
5757

58-
function Base.sortperm(c::StructVector{T};
59-
alg = DEFAULT_UNSTABLE) where {T<:Union{Tuple, NamedTuple}}
58+
function Base.sortperm(c::StructVector{T}) where {T<:Union{Tuple, NamedTuple}}
6059

6160
cols = fieldarrays(c)
6261
x = cols[1]
63-
p = sortperm(x; alg = alg)
62+
p = sortperm(x)
6463
if length(cols) > 1
6564
y = cols[2]
6665
refine_perm!(p, cols, 1, x, y, 1, length(x))

src/structarray.jl

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,36 @@ struct StructArray{T, N, C<:NamedTuple} <: AbstractArray{T, N}
77
fieldarrays::C
88

99
function StructArray{T, N, C}(c) where {T, N, C<:NamedTuple}
10-
length(c) > 0 || error("must have at least one column")
11-
ax = axes(c[1])
12-
length(ax) == N || error("wrong number of dimensions")
13-
for i = 2:length(c)
14-
axes(c[i]) == ax || error("all field arrays must have same shape")
10+
if length(c) > 0
11+
ax = axes(c[1])
12+
length(ax) == N || error("wrong number of dimensions")
13+
for i = 2:length(c)
14+
axes(c[i]) == ax || error("all field arrays must have same shape")
15+
end
1516
end
1617
new{T, N, C}(c)
1718
end
1819
end
1920

21+
_dims(c::NamedTuple) = length(axes(c[1]))
22+
_dims(c::NamedTuple{(), Tuple{}}) = 1
23+
2024
StructArray{T}(c::C) where {T, C<:Tuple} = StructArray{T}(NamedTuple{fields(T)}(c))
21-
StructArray{T}(c::C) where {T, C<:NamedTuple} = StructArray{T, length(size(c[1])), C}(c)
25+
StructArray{T}(c::C) where {T, C<:NamedTuple} = StructArray{T, _dims(c), C}(c)
2226
StructArray{T}(c::C) where {T, C<:Pair} = StructArray{T}(Tuple(c))
2327
StructArray(c::C) where {C<:NamedTuple} = StructArray{eltypes(C)}(c)
24-
StructArray(c::C) where {C<:Tuple} = StructArray{eltypes(C)}(c)
28+
StructArray(c::Tuple; names = nothing) = _structarray(c, names)
2529
StructArray(c::Pair{P, Q}) where {P, Q} = StructArray{Pair{eltype(P), eltype(Q)}}(c)
2630

2731
StructArray{T}(; kwargs...) where {T} = StructArray{T}(values(kwargs))
2832
StructArray(; kwargs...) = StructArray(values(kwargs))
2933

30-
StructArray{T}(args...) where {T} = StructArray{T}(NamedTuple{fields(T)}(args))
34+
@deprecate(StructArray{T}(args...) where {T}, StructArray{T}(args))
35+
36+
_structarray(args::T, ::Nothing) where {T<:Tuple} = StructArray{eltypes(T)}(args)
37+
_structarray(args::Tuple, names) = _structarray(args, Tuple(names))
38+
_structarray(args::Tuple, ::Tuple) = _structarray(args, nothing)
39+
_structarray(args::NTuple{N, Any}, names::NTuple{N, Symbol}) where {N} = StructArray(NamedTuple{names}(args))
3140

3241
const StructVector{T, C<:NamedTuple} = StructArray{T, 1, C}
3342
StructVector{T}(args...; kwargs...) where {T} = StructArray{T}(args...; kwargs...)
@@ -69,10 +78,9 @@ function Base.similar(::Type{StructArray{T, N, C}}, sz::Dims) where {T, N, C}
6978
StructArray{T}(cols)
7079
end
7180

72-
Base.similar(s::StructArray, sz::Tuple) = similar(s, Base.to_shape(sz))
7381
Base.similar(s::StructArray, sz::Base.DimOrInd...) = similar(s, Base.to_shape(sz))
7482
Base.similar(s::StructArray) = similar(s, Base.to_shape(axes(s)))
75-
function Base.similar(s::StructArray{T}, sz::Dims) where {T}
83+
function Base.similar(s::StructArray{T}, sz::Tuple) where {T}
7684
StructArray{T}(map(typ -> similar(typ, sz), fieldarrays(s)))
7785
end
7886

@@ -84,7 +92,9 @@ Base.propertynames(s::StructArray) = fieldnames(typeof(fieldarrays(s)))
8492
staticschema(::Type{<:StructArray{T}}) where {T} = staticschema(T)
8593

8694
Base.size(s::StructArray) = size(fieldarrays(s)[1])
95+
Base.size(s::StructArray{<:Any, <:Any, <:NamedTuple{(), Tuple{}}}) = (0,)
8796
Base.axes(s::StructArray) = axes(fieldarrays(s)[1])
97+
Base.axes(s::StructArray{<:Any, <:Any, <:NamedTuple{(), Tuple{}}}) = (1:0,)
8898

8999
@generated function Base.getindex(x::StructArray{T, N, NamedTuple{names, types}}, I::Int...) where {T, N, names, types}
90100
args = [:(getfield(cols, $i)[I...]) for i in 1:length(names)]

src/utils.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ end
99
map_types(f, ::Type{NamedTuple{names, types}}) where {names, types} =
1010
NamedTuple{names, map_types(f, types)}
1111

12-
all_types(f, ::Type{Tuple{}}, ::Type{T}) where {T<:Tuple} = true
12+
all_types(f, ::Type{Tuple{}}, ::Type{T}) where {T<:Tuple} = false
13+
all_types(f, ::Type{T}, ::Type{Tuple{}}) where {T<:Tuple} = false
14+
all_types(f, ::Type{Tuple{}}, ::Type{Tuple{}}) = true
1315

1416
function all_types(f, ::Type{S}, ::Type{T}) where {S<:Tuple, T<:Tuple}
1517
f(tuple_type_head(S), tuple_type_head(T)) && all_types(f, tuple_type_tail(S), tuple_type_tail(T))

test/runtests.jl

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ end
125125
@test s[1] == (1, "test")
126126
@test Base.getproperty(s, 1) == [1]
127127
@test Base.getproperty(s, 2) == ["test"]
128-
t = StructArray{Tuple{Int, Float64}}([1], [1.2])
128+
t = StructArray{Tuple{Int, Float64}}(([1], [1.2]))
129129
@test t[1] == (1, 1.2)
130130

131131
t[1] = (2, 3)
@@ -139,26 +139,26 @@ end
139139
a = [1.2]
140140
b = [2.3]
141141
@test StructArray(a=a, b=b) == StructArray((a=a, b=b))
142-
@test StructArray{ComplexF64}(re=a, im=b) == StructArray{ComplexF64}(a, b)
142+
@test StructArray{ComplexF64}(re=a, im=b) == StructArray{ComplexF64}((a, b))
143143
f1() = StructArray(a=[1.2], b=["test"])
144144
f2() = StructArray{Pair}(first=[1.2], second=["test"])
145145
t1 = @inferred f1()
146146
t2 = @inferred f2()
147147
@test t1 == StructArray((a=[1.2], b=["test"]))
148-
@test t2 == StructArray{Pair}([1.2], ["test"])
148+
@test t2 == StructArray{Pair}(([1.2], ["test"]))
149149
end
150150

151151
@testset "complex" begin
152152
a, b = [1 2; 3 4], [4 5; 6 7]
153-
t = StructArray{ComplexF64}(a, b)
153+
t = StructArray{ComplexF64}((a, b))
154154
@test t[2,2] == ComplexF64(4, 7)
155-
@test t[2,1:2] == StructArray{ComplexF64}([3, 4], [6, 7])
156-
@test view(t, 2, 1:2) == StructArray{ComplexF64}(view(a, 2, 1:2), view(b, 2, 1:2))
155+
@test t[2,1:2] == StructArray{ComplexF64}(([3, 4], [6, 7]))
156+
@test view(t, 2, 1:2) == StructArray{ComplexF64}((view(a, 2, 1:2), view(b, 2, 1:2)))
157157
end
158158

159159
@testset "copy" begin
160160
a, b = [1 2; 3 4], [4 5; 6 7]
161-
t = StructArray{ComplexF64}(a, b)
161+
t = StructArray{ComplexF64}((a, b))
162162
t2 = @inferred copy(t)
163163
@test t2[1,1] == 1.0 + im*4.0
164164
t2[1,1] = 2.0 + im*4.0
@@ -176,7 +176,7 @@ end
176176
end
177177

178178
@testset "resize!" begin
179-
t = StructArray{Pair}([3, 5], ["a", "b"])
179+
t = StructArray{Pair}(([3, 5], ["a", "b"]))
180180
resize!(t, 5)
181181
@test length(t) == 5
182182
p = 1 => "c"
@@ -185,23 +185,24 @@ end
185185
end
186186

187187
@testset "concat" begin
188-
t = StructArray{Pair}([3, 5], ["a", "b"])
188+
t = StructArray{Pair}(([3, 5], ["a", "b"]))
189189
push!(t, (2 => "c"))
190-
@test t == StructArray{Pair}([3, 5, 2], ["a", "b", "c"])
190+
@test t == StructArray{Pair}(([3, 5, 2], ["a", "b", "c"]))
191191
append!(t, t)
192-
@test t == StructArray{Pair}([3, 5, 2, 3, 5, 2], ["a", "b", "c", "a", "b", "c"])
193-
t = StructArray{Pair}([3, 5], ["a", "b"])
194-
t2 = StructArray{Pair}([1, 6], ["a", "b"])
195-
@test cat(t, t2; dims=1)::StructArray == StructArray{Pair}([3, 5, 1, 6], ["a", "b", "a", "b"]) == vcat(t, t2)
192+
@test t == StructArray{Pair}(([3, 5, 2, 3, 5, 2], ["a", "b", "c", "a", "b", "c"]))
193+
t = StructArray{Pair}(([3, 5], ["a", "b"]))
194+
t2 = StructArray{Pair}(([1, 6], ["a", "b"]))
195+
@test cat(t, t2; dims=1)::StructArray == StructArray{Pair}(([3, 5, 1, 6], ["a", "b", "a", "b"])) == vcat(t, t2)
196196
@test vcat(t, t2) isa StructArray
197-
@test cat(t, t2; dims=2)::StructArray == StructArray{Pair}([3 1; 5 6], ["a" "a"; "b" "b"]) == hcat(t, t2)
197+
@test cat(t, t2; dims=2)::StructArray == StructArray{Pair}(([3 1; 5 6], ["a" "a"; "b" "b"])) == hcat(t, t2)
198198
@test hcat(t, t2) isa StructArray
199199
end
200200

201-
f_infer() = StructArray{ComplexF64}(rand(2,2), rand(2,2))
201+
f_infer() = StructArray{ComplexF64}((rand(2,2), rand(2,2)))
202202

203203
g_infer() = StructArray([(a=(b="1",), c=2)], unwrap = t -> t <: NamedTuple)
204204
tup_infer() = StructArray([(1, 2), (3, 4)])
205+
cols_infer() = StructArray(([1, 2], [1.2, 2.3]))
205206

206207
@testset "inferrability" begin
207208
@inferred f_infer()
@@ -211,10 +212,11 @@ tup_infer() = StructArray([(1, 2), (3, 4)])
211212
@test Tables.columns(s) == (x1 = [1, 3], x2 = [2, 4])
212213
@test s[1] == (1, 2)
213214
@test s[2] == (3, 4)
215+
@inferred cols_infer()
214216
end
215217

216218
@testset "propertynames" begin
217-
a = StructArray{ComplexF64}(Float64[], Float64[])
219+
a = StructArray{ComplexF64}((Float64[], Float64[]))
218220
@test sort(collect(propertynames(a))) == [:im, :re]
219221
end
220222

@@ -239,7 +241,7 @@ end
239241
StructArrays.SkipConstructor(::Type{<:S}) = true
240242

241243
@testset "inner" begin
242-
v = StructArray{S}([1], [1])
244+
v = StructArray{S}(([1], [1]))
243245
@test v[1] == S(1)
244246
@test v[1].y isa Float64
245247
end
@@ -367,32 +369,32 @@ end
367369

368370
@testset "collectpairs" begin
369371
v = (i=>i+1 for i in 1:3)
370-
@test collect_structarray_rec(v) == StructArray{Pair{Int, Int}}([1,2,3], [2,3,4])
372+
@test collect_structarray_rec(v) == StructArray{Pair{Int, Int}}(([1,2,3], [2,3,4]))
371373
@test eltype(collect_structarray_rec(v)) == Pair{Int, Int}
372374

373375
v = (i == 1 ? (1.2 => i+1) : (i => i+1) for i in 1:3)
374-
@test collect_structarray_rec(v) == StructArray{Pair{Real, Int}}([1.2,2,3], [2,3,4])
376+
@test collect_structarray_rec(v) == StructArray{Pair{Real, Int}}(([1.2,2,3], [2,3,4]))
375377
@test eltype(collect_structarray_rec(v)) == Pair{Real, Int}
376378

377379
v = ((a=i,) => (b="a$i",) for i in 1:3)
378-
@test collect_structarray_rec(v) == StructArray{Pair{NamedTuple{(:a,),Tuple{Int64}},NamedTuple{(:b,),Tuple{String}}}}(StructArray((a = [1,2,3],)), StructArray((b = ["a1","a2","a3"],)))
380+
@test collect_structarray_rec(v) == StructArray(StructArray((a = [1,2,3],)) => StructArray((b = ["a1","a2","a3"],)))
379381
@test eltype(collect_structarray_rec(v)) == Pair{NamedTuple{(:a,), Tuple{Int64}}, NamedTuple{(:b,), Tuple{String}}}
380382

381383
v = (i == 1 ? (a="1",) => (b="a$i",) : (a=i,) => (b="a$i",) for i in 1:3)
382-
@test collect_structarray_rec(v) == StructArray{Pair{NamedTuple{(:a,),Tuple{Any}},NamedTuple{(:b,),Tuple{String}}}}(StructArray((a = ["1",2,3],)), StructArray((b = ["a1","a2","a3"],)))
384+
@test collect_structarray_rec(v) == StructArray(StructArray((a = ["1",2,3],)) => StructArray((b = ["a1","a2","a3"],)))
383385
@test eltype(collect_structarray_rec(v)) == Pair{NamedTuple{(:a,), Tuple{Any}}, NamedTuple{(:b,), Tuple{String}}}
384386

385387
# empty
386388
v = ((a=i,) => (b="a$i",) for i in 0:-1)
387-
@test collect_structarray_rec(v) == StructArray{Pair{NamedTuple{(:a,),Tuple{Int64}},NamedTuple{(:b,),Tuple{String}}}}(StructArray((a = Int[],)), StructArray((b = String[],)))
389+
@test collect_structarray_rec(v) == StructArray(StructArray((a = Int[],)) => StructArray((b = String[],)))
388390
@test eltype(collect_structarray_rec(v)) == Pair{NamedTuple{(:a,), Tuple{Int}}, NamedTuple{(:b,), Tuple{String}}}
389391

390392
v = Iterators.filter(t -> t.first.a == 4, ((a=i,) => (b="a$i",) for i in 1:3))
391-
@test collect_structarray_rec(v) == StructArray{Pair{NamedTuple{(:a,),Tuple{Int64}},NamedTuple{(:b,),Tuple{String}}}}(StructArray((a = Int[],)), StructArray((b = String[],)))
393+
@test collect_structarray_rec(v) == StructArray(StructArray((a = Int[],)) => StructArray((b = String[],)))
392394
@test eltype(collect_structarray_rec(v)) == Pair{NamedTuple{(:a,), Tuple{Int}}, NamedTuple{(:b,), Tuple{String}}}
393395

394396
t = collect_structarray_rec((b = 1,) => (a = i,) for i in (2, missing, 3))
395-
s = StructArray{Pair{NamedTuple{(:b,),Tuple{Int64}},NamedTuple{(:a,),Tuple{Union{Missing, Int64}}}}}(StructArray(b = [1,1,1]), StructArray(a = [2, missing, 3]))
397+
s = StructArray(StructArray(b = [1,1,1]) => StructArray(a = [2, missing, 3]))
396398
@test s[1] == t[1]
397399
@test ismissing(t[2].second.a)
398400
@test s[3] == t[3]

0 commit comments

Comments
 (0)