From 0afc01b644e9164cda2e4e0385622427d77ed6f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Mart=C3=ADnez=20Cisneros?= Date: Wed, 19 Jul 2023 22:51:45 +0200 Subject: [PATCH 01/16] Implementing order functions where missings is the smallest value #142 --- README.md | 2 ++ src/Missings.jl | 30 +++++++++++++++++++++++++++++- test/runtests.jl | 7 +++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index aa84323..ab7f85a 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ This package provides additional functionality for working with `missing` values - `Missings.replace` to wrap a collection in a (possibly indexable) iterator replacing `missing` with another value - `Missings.fail` to wrap a collection in a (possibly indexable) iterator throwing an error if `missing` is encountered - `skipmissings` to loop through a collection of iterators excluding indices where any iterators are `missing` +- `missingsmallest(f)` to create a partial order function that behaves as `f` and making `missing` the smallest value +- `missingsless` the standard `isless` function modified so that `missing` is less than any other element ## Contributing and Questions diff --git a/src/Missings.jl b/src/Missings.jl index 08ed26c..1f298f2 100644 --- a/src/Missings.jl +++ b/src/Missings.jl @@ -2,7 +2,7 @@ module Missings export allowmissing, disallowmissing, ismissing, missing, missings, Missing, MissingException, levels, coalesce, passmissing, nonmissingtype, - skipmissings, emptymissing + skipmissings, emptymissing, missingsmallest, missingsless using Base: ismissing, missing, Missing, MissingException @@ -514,4 +514,32 @@ julia> emptymissing(first)([1], 2) """ emptymissing(f) = (x, args...; kwargs...) -> isempty(x) ? missing : f(x, args...; kwargs...) +# Variant of `isless` where `missing` is the smallest value +""" + missingsmallest(f::Function) + +Creates a function of two arguments `x` and `y` that tests whether `x` is less +than `y` such that `missing` is always less than the other argument. In other +words, modifies the partial order function `f` such that `missing` is the +smallest possible value, and all other non-`missing` values are compared +according to `f`. + +See also: [`missingsless`](@ref), the standard order where `missing` is the +smallest possible value. + +# Examples +``` +julia> missingsmallest(isless)(missing, Inf) +true + +julia> missingsless(-Inf, missing) +false +``` +""" +missingsmallest(f) = (x, y) -> ismissing(y) ? false : ismissing(x) ? true : f(x, y) + +" The standard partial order `isless` modified so that `missing` is always the +smallest possible value." +const missingsless = missingsmallest(isless) + end # module diff --git a/test/runtests.jl b/test/runtests.jl index 92e8a2c..cddc768 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -257,4 +257,11 @@ struct CubeRooter end @test emptymissing(fun)(3, 1, c=2) == (1, 2) end +@testset "missingsmallest" begin + @test missingsless(missing, Inf) == true + @test missingsless(-Inf, missing) == false + @test missingsless(3, 4) == true + @test missingsless(-Inf, Inf) == true +end + end From 624b962ad66da853243d7a87f38ceb1a619753db Mon Sep 17 00:00:00 2001 From: Alonso Martinez Date: Mon, 31 Jul 2023 11:16:30 +0200 Subject: [PATCH 02/16] Apply suggestions from code review Co-authored-by: Milan Bouchet-Valat --- README.md | 4 ++-- src/Missings.jl | 6 ++---- test/runtests.jl | 1 + 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ab7f85a..e2da946 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ This package provides additional functionality for working with `missing` values - `Missings.replace` to wrap a collection in a (possibly indexable) iterator replacing `missing` with another value - `Missings.fail` to wrap a collection in a (possibly indexable) iterator throwing an error if `missing` is encountered - `skipmissings` to loop through a collection of iterators excluding indices where any iterators are `missing` -- `missingsmallest(f)` to create a partial order function that behaves as `f` and making `missing` the smallest value -- `missingsless` the standard `isless` function modified so that `missing` is less than any other element +- `missingsmallest(f)` to create a partial order function that treats `missing` as the smallest value and otherwise behaves like `f` +- `missingsless` the standard `isless` function modified to treat `missing` as the smallest value rather than the largest one ## Contributing and Questions diff --git a/src/Missings.jl b/src/Missings.jl index 1f298f2..f88a76c 100644 --- a/src/Missings.jl +++ b/src/Missings.jl @@ -514,9 +514,8 @@ julia> emptymissing(first)([1], 2) """ emptymissing(f) = (x, args...; kwargs...) -> isempty(x) ? missing : f(x, args...; kwargs...) -# Variant of `isless` where `missing` is the smallest value """ - missingsmallest(f::Function) + missingsmallest(f) Creates a function of two arguments `x` and `y` that tests whether `x` is less than `y` such that `missing` is always less than the other argument. In other @@ -524,8 +523,7 @@ words, modifies the partial order function `f` such that `missing` is the smallest possible value, and all other non-`missing` values are compared according to `f`. -See also: [`missingsless`](@ref), the standard order where `missing` is the -smallest possible value. +See also: [`missingsless`](@ref), equivalent to `missingsmallest(isless)` # Examples ``` diff --git a/test/runtests.jl b/test/runtests.jl index cddc768..d095da3 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -260,6 +260,7 @@ end @testset "missingsmallest" begin @test missingsless(missing, Inf) == true @test missingsless(-Inf, missing) == false + @test missingsless(missing, missing) == false @test missingsless(3, 4) == true @test missingsless(-Inf, Inf) == true end From 3ec667a72d333efac11bc9ebf68025512957ca0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Mart=C3=ADnez=20Cisneros?= Date: Mon, 31 Jul 2023 11:18:30 +0200 Subject: [PATCH 03/16] Expanding docstrings per code review --- src/Missings.jl | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/Missings.jl b/src/Missings.jl index f88a76c..e64ed94 100644 --- a/src/Missings.jl +++ b/src/Missings.jl @@ -518,26 +518,51 @@ emptymissing(f) = (x, args...; kwargs...) -> isempty(x) ? missing : f(x, args... missingsmallest(f) Creates a function of two arguments `x` and `y` that tests whether `x` is less -than `y` such that `missing` is always less than the other argument. In other -words, modifies the partial order function `f` such that `missing` is the -smallest possible value, and all other non-`missing` values are compared -according to `f`. +than `y` such that `missing` is always less than the other argument. In other +words, returns a modified version of the partial order function `f` such that +`missing` is the smallest possible value, and all other non-`missing` values are +compared according to `f`. See also: [`missingsless`](@ref), equivalent to `missingsmallest(isless)` # Examples ``` -julia> missingsmallest(isless)(missing, Inf) -true +julia> missingsmallest(Base.isgreater)(missing, Inf) +false julia> missingsless(-Inf, missing) false ``` """ -missingsmallest(f) = (x, y) -> ismissing(y) ? false : ismissing(x) ? true : f(x, y) +@inline missingsmallest(f) = (x, y) -> ismissing(y) ? false : ismissing(x) ? true : f(x, y) " The standard partial order `isless` modified so that `missing` is always the smallest possible value." -const missingsless = missingsmallest(isless) + +""" + missingsless(x, y) + +The standard partial order `isless` modified so that `missing` is always the +smallest possible value. The expected behaviour is the following: +- If neither argument is `missing`, the function behaves exactly as `isless`. +- If `x` is `missing` the result will be `true` regardless of the value of `y`. +- If `y` is `missing` the result will be `false` regardless of the value of `x`. + +See also [`missingsmallest`](@ref), which modifies a partial order function and +yields a function that behaves as the expected behaviour outlined above. + +# Examples +``` +julia> missingsless(missing, Inf) +true + +julia> missingsless(-Inf, missing) +false + +julia> missingsless(missing, missing) +true +``` +""" +missingsless(x, y) = missingsmallest(isless)(x, y) end # module From 4eaa98a802cf4dbbb394ccdfd6f291b75c8bc677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Mart=C3=ADnez=20Cisneros?= Date: Mon, 31 Jul 2023 11:34:06 +0200 Subject: [PATCH 04/16] Expanding missingsmallest testset on other comparison functions --- src/Missings.jl | 4 ++-- test/runtests.jl | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Missings.jl b/src/Missings.jl index e64ed94..38acd94 100644 --- a/src/Missings.jl +++ b/src/Missings.jl @@ -527,8 +527,8 @@ See also: [`missingsless`](@ref), equivalent to `missingsmallest(isless)` # Examples ``` -julia> missingsmallest(Base.isgreater)(missing, Inf) -false +julia> missingsmallest((x, y) -> isless(x, 10*y))(missing, Inf) +true julia> missingsless(-Inf, missing) false diff --git a/test/runtests.jl b/test/runtests.jl index d095da3..19fe8d6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -263,6 +263,13 @@ end @test missingsless(missing, missing) == false @test missingsless(3, 4) == true @test missingsless(-Inf, Inf) == true + + ≪(x, y) = isless(10*x, y) # "Much greater than" function + missings_ll = missingsmallest(≪) + @test missings_ll(missing, Inf) == true + @test missings_ll(-Inf, missing) == false + @test missings_ll(1, 2) == false + @test missings_ll(1, 200) == true end end From 45c8d77a884d7a8cc92af861d926a793457b51e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Mart=C3=ADnez=20Cisneros?= Date: Mon, 11 Sep 2023 11:49:06 +0200 Subject: [PATCH 05/16] Modified API of missingsmallest according to issue 2267 on DataFrames.jl --- README.md | 2 +- src/Missings.jl | 40 +++++++++++++++++++++++++++++++--------- test/runtests.jl | 13 ++++++++----- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index e2da946..b8250e8 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ This package provides additional functionality for working with `missing` values - `Missings.fail` to wrap a collection in a (possibly indexable) iterator throwing an error if `missing` is encountered - `skipmissings` to loop through a collection of iterators excluding indices where any iterators are `missing` - `missingsmallest(f)` to create a partial order function that treats `missing` as the smallest value and otherwise behaves like `f` -- `missingsless` the standard `isless` function modified to treat `missing` as the smallest value rather than the largest one +- `missingsmallest` the standard `isless` function modified to treat `missing` as the smallest value rather than the largest one ## Contributing and Questions diff --git a/src/Missings.jl b/src/Missings.jl index 38acd94..4f774d2 100644 --- a/src/Missings.jl +++ b/src/Missings.jl @@ -2,7 +2,7 @@ module Missings export allowmissing, disallowmissing, ismissing, missing, missings, Missing, MissingException, levels, coalesce, passmissing, nonmissingtype, - skipmissings, emptymissing, missingsmallest, missingsless + skipmissings, emptymissing, missingsmallest using Base: ismissing, missing, Missing, MissingException @@ -514,6 +514,11 @@ julia> emptymissing(first)([1], 2) """ emptymissing(f) = (x, args...; kwargs...) -> isempty(x) ? missing : f(x, args...; kwargs...) +# Only for internal use. Allows dispatch over anonymous functions. +struct MissingSmallest{T} + lt::T +end + """ missingsmallest(f) @@ -523,8 +528,6 @@ words, returns a modified version of the partial order function `f` such that `missing` is the smallest possible value, and all other non-`missing` values are compared according to `f`. -See also: [`missingsless`](@ref), equivalent to `missingsmallest(isless)` - # Examples ``` julia> missingsmallest((x, y) -> isless(x, 10*y))(missing, Inf) @@ -534,13 +537,14 @@ julia> missingsless(-Inf, missing) false ``` """ -@inline missingsmallest(f) = (x, y) -> ismissing(y) ? false : ismissing(x) ? true : f(x, y) +missingsmallest(f) = MissingSmallest(f) + " The standard partial order `isless` modified so that `missing` is always the smallest possible value." """ - missingsless(x, y) + missingsmallest(x, y) The standard partial order `isless` modified so that `missing` is always the smallest possible value. The expected behaviour is the following: @@ -553,16 +557,34 @@ yields a function that behaves as the expected behaviour outlined above. # Examples ``` -julia> missingsless(missing, Inf) +julia> missingsmallest(missing, Inf) true -julia> missingsless(-Inf, missing) +julia> missingsmallest(-Inf, missing) false -julia> missingsless(missing, missing) +julia> missingsmallest(missing, missing) true ``` """ -missingsless(x, y) = missingsmallest(isless)(x, y) +missingsmallest(x, y) = missingsmallest(isless)(x, y) + +(ms::MissingSmallest)(x, y) = ismissing(y) ? false : ismissing(x) ? true : ms.lt(x, y) + +# Some optimizations +const _MissingSmallest = Union{MissingSmallest, typeof(missingsmallest)} + +@static if isdefined(Base.Sort, :MissingOptimization) && isdefined(Base.Sort, :_sort!) + function Base.Sort._sort!(v::AbstractVector, a::Base.Sort.MissingOptimization, + o::Base.Order.Lt{<:_MissingSmallest}, kw) + # put missing at beginning + Base.Sort._sort!(v, a.next, withoutmissingordering(o), kw...;hi=new_hi) + end + function Base.Sort._sort!(v::AbstractVector, a::Base.Sort.MissingOptimization, + o::Base.Order.ReverseOrdering{Base.Order.Lt{<:_MissingSmallest}}, kw) + # put missing at end + Base.Sort._sort!(v, a.next, ReverseOrdering(withoutmissingordering(o.fwd)), kw...; lo=new_lo) + end +end end # module diff --git a/test/runtests.jl b/test/runtests.jl index 19fe8d6..15e52e9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -258,11 +258,11 @@ struct CubeRooter end end @testset "missingsmallest" begin - @test missingsless(missing, Inf) == true - @test missingsless(-Inf, missing) == false - @test missingsless(missing, missing) == false - @test missingsless(3, 4) == true - @test missingsless(-Inf, Inf) == true + @test missingsmallest(missing, Inf) == true + @test missingsmallest(-Inf, missing) == false + @test missingsmallest(missing, missing) == false + @test missingsmallest(3, 4) == true + @test missingsmallest(-Inf, Inf) == true ≪(x, y) = isless(10*x, y) # "Much greater than" function missings_ll = missingsmallest(≪) @@ -270,6 +270,9 @@ end @test missings_ll(-Inf, missing) == false @test missings_ll(1, 2) == false @test missings_ll(1, 200) == true + + @test_throws MethodError missingsmallest(isless)(isless) + @test missingsmallest !== missingsmallest(isless) end end From ffc24438cfdcce99bdc7e2e47e9f0d37ac121494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Mart=C3=ADnez=20Cisneros?= Date: Sat, 23 Sep 2023 13:22:08 +0200 Subject: [PATCH 06/16] Removed Optimizations & enhanced missingsmallest(x, y) documentation --- src/Missings.jl | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/src/Missings.jl b/src/Missings.jl index 4f774d2..051a411 100644 --- a/src/Missings.jl +++ b/src/Missings.jl @@ -539,10 +539,6 @@ false """ missingsmallest(f) = MissingSmallest(f) - -" The standard partial order `isless` modified so that `missing` is always the -smallest possible value." - """ missingsmallest(x, y) @@ -552,11 +548,22 @@ smallest possible value. The expected behaviour is the following: - If `x` is `missing` the result will be `true` regardless of the value of `y`. - If `y` is `missing` the result will be `false` regardless of the value of `x`. -See also [`missingsmallest`](@ref), which modifies a partial order function and -yields a function that behaves as the expected behaviour outlined above. +See also [`missingsmallest`](@ref), which is equivalent to using +`missingsmallest(isless)`. These functions can be used together with sorting +functions such that the first elements of the newly sorted Array are placed +first. # Examples ``` +julia> v = [missing, 10, missing, 1, 2] +julia> sort(v, lt=missingsmallest) +5-element Vector{Union{Missing, Int64}}: + missing + missing + 1 + 2 + 10 + julia> missingsmallest(missing, Inf) true @@ -571,20 +578,4 @@ missingsmallest(x, y) = missingsmallest(isless)(x, y) (ms::MissingSmallest)(x, y) = ismissing(y) ? false : ismissing(x) ? true : ms.lt(x, y) -# Some optimizations -const _MissingSmallest = Union{MissingSmallest, typeof(missingsmallest)} - -@static if isdefined(Base.Sort, :MissingOptimization) && isdefined(Base.Sort, :_sort!) - function Base.Sort._sort!(v::AbstractVector, a::Base.Sort.MissingOptimization, - o::Base.Order.Lt{<:_MissingSmallest}, kw) - # put missing at beginning - Base.Sort._sort!(v, a.next, withoutmissingordering(o), kw...;hi=new_hi) - end - function Base.Sort._sort!(v::AbstractVector, a::Base.Sort.MissingOptimization, - o::Base.Order.ReverseOrdering{Base.Order.Lt{<:_MissingSmallest}}, kw) - # put missing at end - Base.Sort._sort!(v, a.next, ReverseOrdering(withoutmissingordering(o.fwd)), kw...; lo=new_lo) - end -end - -end # module +end # module \ No newline at end of file From d17a82a076a139fb8a98cd99ea9629bb8ed446de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Mart=C3=ADnez=20Cisneros?= Date: Mon, 2 Oct 2023 17:44:03 +0200 Subject: [PATCH 07/16] Ammended wrong docstrings + added better examples --- src/Missings.jl | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Missings.jl b/src/Missings.jl index 051a411..77ec7d0 100644 --- a/src/Missings.jl +++ b/src/Missings.jl @@ -528,12 +528,17 @@ words, returns a modified version of the partial order function `f` such that `missing` is the smallest possible value, and all other non-`missing` values are compared according to `f`. +The traditional `isless` function modified to treat `missing` as the smallest +value can be accessed by using the 2-argument `missingsmallest(x, y)` function, +see [`missingsmallest`](@ref). + # Examples ``` -julia> missingsmallest((x, y) -> isless(x, 10*y))(missing, Inf) +julia> ismuchless = missingsmallest((x, y) -> isless(x, 10*y)) +julia> ismuchless(1, 100) true -julia> missingsless(-Inf, missing) +julia> ismuchless(-Inf, missing) false ``` """ @@ -548,10 +553,10 @@ smallest possible value. The expected behaviour is the following: - If `x` is `missing` the result will be `true` regardless of the value of `y`. - If `y` is `missing` the result will be `false` regardless of the value of `x`. -See also [`missingsmallest`](@ref), which is equivalent to using -`missingsmallest(isless)`. These functions can be used together with sorting -functions such that the first elements of the newly sorted Array are placed -first. +See also [`missingsmallest`](@ref), the 1-argument function which takes a +partial ordering function (like `isless`) and modifies it to treat `missing` as +explained above. These functions can be used together with sorting functions +such that the first elements of the newly sorted Array are placed first. # Examples ``` From 3e07818f0f76d1fa3ed4a6838e1b8c967bbdfddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Mart=C3=ADnez=20Cisneros?= Date: Wed, 4 Oct 2023 13:27:33 +0200 Subject: [PATCH 08/16] Applied first round of comments from LillithHafner & nalimilan --- README.md | 2 +- src/Missings.jl | 25 ++++++++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b8250e8..347d151 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ This package provides additional functionality for working with `missing` values - `Missings.fail` to wrap a collection in a (possibly indexable) iterator throwing an error if `missing` is encountered - `skipmissings` to loop through a collection of iterators excluding indices where any iterators are `missing` - `missingsmallest(f)` to create a partial order function that treats `missing` as the smallest value and otherwise behaves like `f` -- `missingsmallest` the standard `isless` function modified to treat `missing` as the smallest value rather than the largest one +- `missingsmallest`: the standard `isless` function modified to treat `missing` as the smallest value rather than the largest one ## Contributing and Questions diff --git a/src/Missings.jl b/src/Missings.jl index 77ec7d0..c838169 100644 --- a/src/Missings.jl +++ b/src/Missings.jl @@ -522,9 +522,9 @@ end """ missingsmallest(f) -Creates a function of two arguments `x` and `y` that tests whether `x` is less +Return a function of two arguments `x` and `y` that tests whether `x` is less than `y` such that `missing` is always less than the other argument. In other -words, returns a modified version of the partial order function `f` such that +words, return a modified version of the partial order function `f` such that `missing` is the smallest possible value, and all other non-`missing` values are compared according to `f`. @@ -548,20 +548,22 @@ missingsmallest(f) = MissingSmallest(f) missingsmallest(x, y) The standard partial order `isless` modified so that `missing` is always the -smallest possible value. The expected behaviour is the following: +smallest possible value: - If neither argument is `missing`, the function behaves exactly as `isless`. - If `x` is `missing` the result will be `true` regardless of the value of `y`. - If `y` is `missing` the result will be `false` regardless of the value of `x`. -See also [`missingsmallest`](@ref), the 1-argument function which takes a -partial ordering function (like `isless`) and modifies it to treat `missing` as -explained above. These functions can be used together with sorting functions -such that the first elements of the newly sorted Array are placed first. +See also the 1-argument method which takes a partial ordering function (like +`isless`) and modifies it to treat `missing` as explained above. These functions +can be used together with sorting functions so that missing values are sorted +first. This is useful in particular so that when sorting in reverse order +missing values appear at the end. # Examples ``` julia> v = [missing, 10, missing, 1, 2] julia> sort(v, lt=missingsmallest) + 5-element Vector{Union{Missing, Int64}}: missing missing @@ -569,6 +571,15 @@ julia> sort(v, lt=missingsmallest) 2 10 +julia> sort(v, lt=missingsmallest, rev=true) + +5-element Vector{Union{Missing, Int64}}: + 10 + 2 + 1 + missing + missing + julia> missingsmallest(missing, Inf) true From 8e4aa6d1546f088b427d158e00845910eeda1635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Mart=C3=ADnez=20Cisneros?= Date: Fri, 6 Oct 2023 12:24:39 +0200 Subject: [PATCH 09/16] Removing unhelpful examples in docstrings --- src/Missings.jl | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Missings.jl b/src/Missings.jl index c838169..f2a659d 100644 --- a/src/Missings.jl +++ b/src/Missings.jl @@ -528,17 +528,21 @@ words, return a modified version of the partial order function `f` such that `missing` is the smallest possible value, and all other non-`missing` values are compared according to `f`. -The traditional `isless` function modified to treat `missing` as the smallest -value can be accessed by using the 2-argument `missingsmallest(x, y)` function, -see [`missingsmallest`](@ref). +The behavior of the standard `isless` function modified to treat `missing` as +the smallest value can be obtained by calling the 2-argument `missingsmallest(x, +y)` function. This is equivalent to `missingsmallest(isless)(x, y)`. # Examples ``` -julia> ismuchless = missingsmallest((x, y) -> isless(x, 10*y)) -julia> ismuchless(1, 100) +julia> lengthmissing = passmissing(length) +julia> isshorter = missingsmallest((s1, s2) -> isless(lengthmissing(s1), lengthmissing(s2))) +julia> isshorter("short", "longstring") true -julia> ismuchless(-Inf, missing) +julia> isshorter("longstring", "short") +false + +julia> isshorter("", missing) # Is shorter than length 0? false ``` """ From 74be1518173cc42086c2d7ef578633c7e4b108af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Mart=C3=ADnez=20Cisneros?= Date: Fri, 6 Oct 2023 12:25:02 +0200 Subject: [PATCH 10/16] Expanding missingsmallest tests on other types and order functions --- test/runtests.jl | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 15e52e9..3d7abc4 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -264,12 +264,21 @@ end @test missingsmallest(3, 4) == true @test missingsmallest(-Inf, Inf) == true - ≪(x, y) = isless(10*x, y) # "Much greater than" function - missings_ll = missingsmallest(≪) - @test missings_ll(missing, Inf) == true - @test missings_ll(-Inf, missing) == false - @test missings_ll(1, 2) == false - @test missings_ll(1, 200) == true + @test missingsmallest("a", "b") == true + @test missingsmallest("short", missing) == false + @test missingsmallest(missing, "") == true + + @test missingsmallest((1, 2), (3, 4)) == true + @test missingsmallest((3, 4), (1, 2)) == false + @test missingsmallest(missing, (1e3, 1e4)) == true + + # Compare strings by length, not lexicographically + lengthmissing = passmissing(length) + isshorter = missingsmallest((s1, s2) -> isless(lengthmissing(s1), lengthmissing(s2))) + @test isshorter("short", "longstring") == true + @test isshorter("longstring", "short") == false + @test isshorter(missing, "short") == true + @test isshorter("", missing) == false @test_throws MethodError missingsmallest(isless)(isless) @test missingsmallest !== missingsmallest(isless) From a0e9128a2b69630d4533dd31e7121cecd06f26c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Mart=C3=ADnez=20Cisneros?= Date: Mon, 9 Oct 2023 19:12:23 +0200 Subject: [PATCH 11/16] Fixing mistakes in examples' expected output & simplified examples --- src/Missings.jl | 11 ++++------- test/runtests.jl | 3 +-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Missings.jl b/src/Missings.jl index f2a659d..c03ff87 100644 --- a/src/Missings.jl +++ b/src/Missings.jl @@ -534,8 +534,7 @@ y)` function. This is equivalent to `missingsmallest(isless)(x, y)`. # Examples ``` -julia> lengthmissing = passmissing(length) -julia> isshorter = missingsmallest((s1, s2) -> isless(lengthmissing(s1), lengthmissing(s2))) +julia> isshorter = missingsmallest((s1, s2) -> isless(length(s1), length(s2))) julia> isshorter("short", "longstring") true @@ -554,8 +553,8 @@ missingsmallest(f) = MissingSmallest(f) The standard partial order `isless` modified so that `missing` is always the smallest possible value: - If neither argument is `missing`, the function behaves exactly as `isless`. -- If `x` is `missing` the result will be `true` regardless of the value of `y`. - If `y` is `missing` the result will be `false` regardless of the value of `x`. +- If `x` is `missing` the result will be `true` unless `y` is `missing`. See also the 1-argument method which takes a partial ordering function (like `isless`) and modifies it to treat `missing` as explained above. These functions @@ -564,8 +563,7 @@ first. This is useful in particular so that when sorting in reverse order missing values appear at the end. # Examples -``` -julia> v = [missing, 10, missing, 1, 2] +```jldoctest julia> sort(v, lt=missingsmallest) 5-element Vector{Union{Missing, Int64}}: @@ -591,8 +589,7 @@ julia> missingsmallest(-Inf, missing) false julia> missingsmallest(missing, missing) -true -``` +false """ missingsmallest(x, y) = missingsmallest(isless)(x, y) diff --git a/test/runtests.jl b/test/runtests.jl index 3d7abc4..54daa49 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -273,8 +273,7 @@ end @test missingsmallest(missing, (1e3, 1e4)) == true # Compare strings by length, not lexicographically - lengthmissing = passmissing(length) - isshorter = missingsmallest((s1, s2) -> isless(lengthmissing(s1), lengthmissing(s2))) + isshorter = missingsmallest((s1, s2) -> isless(length(s1), length(s2))) @test isshorter("short", "longstring") == true @test isshorter("longstring", "short") == false @test isshorter(missing, "short") == true From 44dcab26356c667559769c357a9e66070c4d85b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Mart=C3=ADnez=20Cisneros?= Date: Mon, 9 Oct 2023 21:10:18 +0200 Subject: [PATCH 12/16] Removed confusing comment on docstrings --- src/Missings.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Missings.jl b/src/Missings.jl index c03ff87..4327638 100644 --- a/src/Missings.jl +++ b/src/Missings.jl @@ -541,7 +541,7 @@ true julia> isshorter("longstring", "short") false -julia> isshorter("", missing) # Is shorter than length 0? +julia> isshorter("", missing) false ``` """ From b4740db5d3abfd318baea0d48d8b49f4e0f30464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 4 Mar 2024 09:24:27 +0100 Subject: [PATCH 13/16] Apply suggestions from code review Co-authored-by: Milan Bouchet-Valat --- src/Missings.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Missings.jl b/src/Missings.jl index 4327638..955656c 100644 --- a/src/Missings.jl +++ b/src/Missings.jl @@ -534,7 +534,8 @@ y)` function. This is equivalent to `missingsmallest(isless)(x, y)`. # Examples ``` -julia> isshorter = missingsmallest((s1, s2) -> isless(length(s1), length(s2))) +julia> isshorter = missingsmallest((s1, s2) -> isless(length(s1), length(s2))); + julia> isshorter("short", "longstring") true @@ -574,7 +575,6 @@ julia> sort(v, lt=missingsmallest) 10 julia> sort(v, lt=missingsmallest, rev=true) - 5-element Vector{Union{Missing, Int64}}: 10 2 From a36140591ce66745f51af4f9520aa3b2ff259065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Mart=C3=ADnez=20Cisneros?= Date: Fri, 29 Mar 2024 18:26:15 +0100 Subject: [PATCH 14/16] Broadening Exception catching to pass tests on nightly --- test/runtests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 54daa49..dd3867c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -158,7 +158,7 @@ struct CubeRooter end @test disallowmissing(Any[:a]) == [:a] @test disallowmissing(Any[:a]) isa AbstractVector{Any} @test_throws MethodError disallowmissing([1, missing]) - @test_throws MethodError disallowmissing([missing]) + @test_throws Union{MethodError, ArgumentError} disallowmissing([missing]) @test disallowmissing(Union{Int, Missing}[1 1]) == [1 1] @test disallowmissing(Union{Int, Missing}[1 1]) isa AbstractArray{Int, 2} @@ -167,7 +167,7 @@ struct CubeRooter end @test disallowmissing([:a 1]) == [:a 1] @test disallowmissing([:a 1]) isa AbstractArray{Any, 2} @test_throws MethodError disallowmissing([1 missing]) - @test_throws MethodError disallowmissing([missing missing]) + @test_throws Union{MethodError, MethodError} disallowmissing([missing missing]) # Lifting ## functor From d4b8482dfe3d69edaae217c0631b7a0b84c6bdd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alonso=20Mart=C3=ADnez=20Cisneros?= Date: Fri, 29 Mar 2024 18:28:55 +0100 Subject: [PATCH 15/16] Fixing silly mistake on previous commit --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index dd3867c..c8c9963 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -167,7 +167,7 @@ struct CubeRooter end @test disallowmissing([:a 1]) == [:a 1] @test disallowmissing([:a 1]) isa AbstractArray{Any, 2} @test_throws MethodError disallowmissing([1 missing]) - @test_throws Union{MethodError, MethodError} disallowmissing([missing missing]) + @test_throws Union{MethodError, ArgumentError} disallowmissing([missing missing]) # Lifting ## functor From e8bd044cdfcb171ef9da7b39bdc7df9bfd300ce7 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Sat, 6 Apr 2024 12:40:40 +0200 Subject: [PATCH 16/16] Update src/Missings.jl --- src/Missings.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Missings.jl b/src/Missings.jl index 955656c..e3119dd 100644 --- a/src/Missings.jl +++ b/src/Missings.jl @@ -566,7 +566,6 @@ missing values appear at the end. # Examples ```jldoctest julia> sort(v, lt=missingsmallest) - 5-element Vector{Union{Missing, Int64}}: missing missing