Skip to content

Commit 13a9bad

Browse files
authored
Add Array constructors and convert methods (#420)
Consistent with existing `similar` methods and the `Array` constructor, ensure `T(::CategoricalArray{U})` and `convert(T, ::CategoricalArray{U})` return an `Array{U}` for `T` in `Array`, `Vector`, `Matrix`. Same for `SubArray`s of `CategoricalArray`s. This avoids creating `Array{<:CategoricalValue}` objects which are inefficient and unlikely to be what users want.
1 parent 11d43c1 commit 13a9bad

File tree

2 files changed

+112
-5
lines changed

2 files changed

+112
-5
lines changed

src/array.jl

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## Code for CategoricalArray
22

3-
import Base: Array, convert, collect, copy, getindex, setindex!, similar, size,
3+
import Base: Array, Vector, Matrix, convert, collect, copy, getindex,
4+
setindex!, similar, size,
45
unique, unique!, vcat, in, summary, float, complex, copyto!
56

67
# Used for keyword argument default value
@@ -410,6 +411,12 @@ convert(::Type{CategoricalArray{T, N}}, A::CategoricalArray{T, N}) where {T, N}
410411
convert(::Type{CategoricalArray{T}}, A::CategoricalArray{T}) where {T} = A
411412
convert(::Type{CategoricalArray}, A::CategoricalArray) = A
412413

414+
convert(::Type{Array{S, N}}, A::CatArrOrSub{T, N}) where {S, T, N} =
415+
collect(S, A)
416+
convert(::Type{Array}, A::CatArrOrSub) = unwrap.(A)
417+
convert(::Type{Vector}, A::CatArrOrSub) = unwrap.(A)
418+
convert(::Type{Matrix}, A::CatArrOrSub) = unwrap.(A)
419+
413420
function Base.:(==)(A::CategoricalArray{S}, B::CategoricalArray{T}) where {S, T}
414421
if size(A) != size(B)
415422
return false
@@ -1048,8 +1055,10 @@ function in(x::CategoricalValue, y::CategoricalArray{T, N, R}) where {T, N, R}
10481055
end
10491056
end
10501057

1051-
Array(A::CategoricalArray{T}) where {T} = Array{T}(A)
1052-
collect(A::CategoricalArray) = copy(A)
1058+
Array(A::CatArrOrSub{T}) where {T} = Array{T}(A)
1059+
Vector(A::CatArrOrSub{T}) where {T} = Vector{T}(A)
1060+
Matrix(A::CatArrOrSub{T}) where {T} = Matrix{T}(A)
1061+
collect(A::CatArrOrSub) = copy(A)
10531062

10541063
# Defined for performance
10551064
collect(x::Base.SkipMissing{<: CatArrOrSub{T}}) where {T} =
@@ -1119,7 +1128,7 @@ function Base.sort!(v::CategoricalVector;
11191128
levs = eltype(v) >: Missing ?
11201129
eltype(v)[i == 0 ? missing : CategoricalValue(v.pool, i) for i in 0:length(v.pool)] :
11211130
eltype(v)[CategoricalValue(v.pool, i) for i in 1:length(v.pool)]
1122-
sortedlevs = sort!(Vector(view(levs, seen)), order=ord)
1131+
sortedlevs = sort!(Vector{eltype(levs)}(view(levs, seen)), order=ord)
11231132
levelsmap = something.(indexin(sortedlevs, levs))
11241133
j = 0
11251134
refs = v.refs

test/13_arraycommon.jl

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1330,18 +1330,116 @@ end
13301330
@test levels(x) == [2, 1, 3, 4]
13311331
end
13321332

1333-
@testset "Array(::CategoricalArray{T}) produces Array{T}" begin
1333+
@testset "Array(::CatArrOrSub{T}) produces Array{T}" begin
13341334
x = [1,1,2,2]
13351335
y = categorical(x)
13361336
z = Array(y)
13371337
@test typeof(x) == typeof(z)
13381338
@test z == x
1339+
z = Array(view(x, 1:4))
1340+
@test typeof(x) == typeof(z)
1341+
@test z == x
13391342

13401343
x = [1,1,2,missing]
13411344
y = categorical(x)
13421345
z = Array(y)
13431346
@test typeof(x) == typeof(z)
13441347
@test z x
1348+
z = Array(view(x, 1:4))
1349+
@test typeof(x) == typeof(z)
1350+
@test z x
1351+
1352+
x = [1,1,2,2]
1353+
y = categorical(x)
1354+
z = Vector(y)
1355+
@test typeof(x) == typeof(z)
1356+
@test z == x
1357+
z = Vector(view(x, 1:4))
1358+
@test typeof(x) == typeof(z)
1359+
@test z == x
1360+
1361+
x = [1,1,2,missing]
1362+
y = categorical(x)
1363+
z = Vector(y)
1364+
@test typeof(x) == typeof(z)
1365+
@test z x
1366+
z = Vector(view(x, 1:4))
1367+
@test typeof(x) == typeof(z)
1368+
@test z x
1369+
1370+
x = [1 1 2 2]
1371+
y = categorical(x)
1372+
z = Matrix(y)
1373+
@test typeof(x) == typeof(z)
1374+
@test z == x
1375+
z = Matrix(view(x, :, 1:4))
1376+
@test typeof(x) == typeof(z)
1377+
@test z == x
1378+
1379+
x = [1 1 2 missing]
1380+
y = categorical(x)
1381+
z = Matrix(y)
1382+
@test typeof(x) == typeof(z)
1383+
@test z x
1384+
z = Matrix(view(x, :, 1:4))
1385+
@test typeof(x) == typeof(z)
1386+
@test z x
1387+
end
1388+
1389+
@testset "convert(Array, ::CatArrOrSub{T}) produces Array{T}" begin
1390+
x = [1,1,2,2]
1391+
y = categorical(x)
1392+
z = convert(Array, y)
1393+
@test typeof(x) == typeof(z)
1394+
@test z == x
1395+
z = Array(view(x, 1:4))
1396+
@test typeof(x) == typeof(z)
1397+
@test z == x
1398+
1399+
x = [1,1,2,missing]
1400+
y = categorical(x)
1401+
z = convert(Array, y)
1402+
@test typeof(x) == typeof(z)
1403+
@test z x
1404+
z = Array(view(x, 1:4))
1405+
@test typeof(x) == typeof(z)
1406+
@test z x
1407+
1408+
x = [1,1,2,2]
1409+
y = categorical(x)
1410+
z = convert(Vector, y)
1411+
@test typeof(x) == typeof(z)
1412+
@test z == x
1413+
z = Vector(view(x, 1:4))
1414+
@test typeof(x) == typeof(z)
1415+
@test z == x
1416+
1417+
x = [1,1,2,missing]
1418+
y = categorical(x)
1419+
z = convert(Vector, y)
1420+
@test typeof(x) == typeof(z)
1421+
@test z x
1422+
z = Vector(view(x, 1:4))
1423+
@test typeof(x) == typeof(z)
1424+
@test z x
1425+
1426+
x = [1 1 2 2]
1427+
y = categorical(x)
1428+
z = convert(Matrix, y)
1429+
@test typeof(x) == typeof(z)
1430+
@test z == x
1431+
z = Matrix(view(x, :, 1:4))
1432+
@test typeof(x) == typeof(z)
1433+
@test z == x
1434+
1435+
x = [1 1 2 missing]
1436+
y = categorical(x)
1437+
z = convert(Matrix, y)
1438+
@test typeof(x) == typeof(z)
1439+
@test z x
1440+
z = Matrix(view(x, :, 1:4))
1441+
@test typeof(x) == typeof(z)
1442+
@test z x
13451443
end
13461444

13471445
@testset "Array{T} constructors and convert" begin

0 commit comments

Comments
 (0)