Skip to content

Commit 76e1d1c

Browse files
bkaminsnalimilan
authored andcommitted
Make sure that CategoricalArray constructor allocates new pool and refs (JuliaData#110)
Following the convention established in Base.
1 parent 8207ff7 commit 76e1d1c

File tree

2 files changed

+22
-11
lines changed

2 files changed

+22
-11
lines changed

src/array.jl

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Similar to definition above, but uses reference type `R` instead of the default
3535
3636
CategoricalArray(A::AbstractArray; ordered::Bool=false)
3737
38-
Construct a `CategoricalArray` with the values from `A` and the same element type.
38+
Construct a new `CategoricalArray` with the values from `A` and the same element type.
3939
4040
If the element type supports it, levels are sorted in ascending order;
4141
else, they are kept in their order of appearance in `A`. The `ordered` keyword
@@ -154,16 +154,13 @@ CategoricalMatrix{T}(m::Int, n::Int; ordered=false) where {T} =
154154

155155
## Constructors from arrays
156156

157-
# This method is needed to ensure that a copy of the pool is always made
158-
# so that ordered!() does not affect the original array
159157
function CategoricalArray{T, N, R}(A::CategoricalArray{S, N, Q};
160158
ordered=_isordered(A)) where {S, T, N, Q, R}
161159
V = unwrap_catvaluetype(T)
162160
res = convert(CategoricalArray{V, N, R}, A)
163-
if res.pool === A.pool # convert() only makes a copy when necessary
164-
res = CategoricalArray{V, N}(res.refs, deepcopy(res.pool))
165-
end
166-
ordered!(res, ordered)
161+
refs = res.refs === A.refs ? deepcopy(res.refs) : res.refs
162+
pool = res.pool === A.pool ? deepcopy(res.pool) : res.pool
163+
ordered!(CategoricalArray{V, N}(refs, pool), ordered)
167164
end
168165

169166
function CategoricalArray{T, N, R}(A::AbstractArray; ordered=_isordered(A)) where {T, N, R}

test/13_arraycommon.jl

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ end
579579
@test y.refs == x.refs
580580
@test index(y.pool) == index(x.pool)
581581
@test levels(y) == levels(x)
582-
@test (y.refs === x.refs) == (eltype(x.refs) === eltype(y.refs))
582+
@test y.refs !== x.refs
583583
@test y.pool !== x.pool
584584
end
585585
for y in (categorical(x),
@@ -591,7 +591,7 @@ end
591591
@test y.refs == x.refs
592592
@test index(y.pool) == index(x.pool)
593593
@test levels(y) == levels(x)
594-
@test (y.refs === x.refs) == (eltype(x.refs) === eltype(y.refs))
594+
@test y.refs !== x.refs
595595
@test y.pool !== x.pool
596596
end
597597
for y in (CategoricalArray(x, ordered=ordered),
@@ -611,7 +611,7 @@ end
611611
@test y.refs == x.refs
612612
@test index(y.pool) == index(x.pool)
613613
@test levels(y) == levels(x)
614-
@test (y.refs === x.refs) == (eltype(x.refs) === eltype(y.refs))
614+
@test y.refs !== x.refs
615615
@test y.pool !== x.pool
616616
end
617617
for y in (categorical(x, ordered=ordered),
@@ -623,7 +623,7 @@ end
623623
@test y.refs == x.refs
624624
@test index(y.pool) == index(x.pool)
625625
@test levels(y) == levels(x)
626-
@test (y.refs === x.refs) == (eltype(x.refs) === eltype(y.refs))
626+
@test y.refs !== x.refs
627627
@test y.pool !== x.pool
628628
end
629629
for y in (convert(CategoricalArray, x),
@@ -747,4 +747,18 @@ end
747747
@test vcat(z1, z2) isa CategoricalVector{Float64}
748748
end
749749

750+
@testset "categorical() makes a copy of pool and refs" begin
751+
xs = Any[Int8[1:10;], [Int8[1:10;]; missing]]
752+
for x in xs, o1 in [true, false], o2 in [true, false], T in [Int64, Int8]
753+
y = categorical(x, ordered=o1)
754+
if x === xs[1]
755+
z = CategoricalArray{T}(y, ordered=o2)
756+
else
757+
z = CategoricalArray{Union{T, Missing}}(y, ordered=o2)
758+
end
759+
@test z.refs !== y.refs
760+
@test z.pool !== y.pool
761+
end
762+
end
763+
750764
end

0 commit comments

Comments
 (0)