Skip to content

Commit 59e1ef0

Browse files
nalimilankleinschmidt
authored andcommitted
Add levels (#12)
* Add levels Currently lives in Missings.jl, which isn't the most logical place. This will allow StatsModels to drop the dependency on Missings, while CategoricalArrays will continue adding a specialized method to it. * Fix sorting * Bump version to 1.1.0
1 parent 0f74b43 commit 59e1ef0

File tree

3 files changed

+51
-1
lines changed

3 files changed

+51
-1
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "DataAPI"
22
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
33
authors = ["quinnj <[email protected]>"]
4-
version = "1.0.1"
4+
version = "1.1.0"
55

66
[compat]
77
julia = "1"

src/DataAPI.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,26 @@ definition.
7373
"""
7474
function describe end
7575

76+
"""
77+
levels(x)
78+
79+
Return a vector of unique values which occur or could occur in collection `x`,
80+
omitting `missing` even if present. Values are returned in the preferred order
81+
for the collection, with the result of [`sort`](@ref) as a default.
82+
83+
Contrary to [`unique`](@ref), this function may return values which do not
84+
actually occur in the data, and does not preserve their order of appearance in `x`.
85+
"""
86+
function levels(x)
87+
T = Base.nonmissingtype(eltype(x))
88+
levs = convert(AbstractArray{T}, filter!(!ismissing, unique(x)))
89+
try
90+
sort!(levs)
91+
catch
92+
end
93+
levs
94+
end
95+
7696
"""
7797
Between(first, last)
7898

test/runtests.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,36 @@ end
2727

2828
end
2929

30+
@testset "levels" begin
31+
32+
@test DataAPI.levels(1:1) ==
33+
DataAPI.levels([1]) ==
34+
DataAPI.levels([1, missing]) ==
35+
DataAPI.levels([missing, 1]) ==
36+
[1]
37+
@test DataAPI.levels(2:-1:1) ==
38+
DataAPI.levels([2, 1]) ==
39+
DataAPI.levels(Any[2, 1]) ==
40+
DataAPI.levels([2, missing, 1]) ==
41+
[1, 2]
42+
@test DataAPI.levels([missing, "a", "c", missing, "b"]) == ["a", "b", "c"]
43+
@test DataAPI.levels([Complex(0, 1), Complex(1, 0), missing]) ==
44+
[Complex(0, 1), Complex(1, 0)]
45+
@test typeof(DataAPI.levels([1])) ===
46+
typeof(DataAPI.levels([1, missing])) ===
47+
Vector{Int}
48+
@test typeof(DataAPI.levels(["a"])) ===
49+
typeof(DataAPI.levels(["a", missing])) ===
50+
Vector{String}
51+
@test typeof(DataAPI.levels(Real[1])) ===
52+
typeof(DataAPI.levels(Union{Real,Missing}[1, missing])) ===
53+
Vector{Real}
54+
@test typeof(DataAPI.levels(trues(1))) === Vector{Bool}
55+
@test isempty(DataAPI.levels([missing]))
56+
@test isempty(DataAPI.levels([]))
57+
58+
end
59+
3060
@testset "Between" begin
3161

3262
for x in (1, :a), y in (1, :a)

0 commit comments

Comments
 (0)