If we have an iterator generating (repeat length, value)-tuples in A
, we can easily obtain a maxrep_minval(A)
function using the lexicographic ordering of tuples.
Definition of the iterator RepVal(A)
generating (repeat length, value)-tuples in A
:
function repeatlength(A, i)
k = 1
@inbounds while i + k ≤ lastindex(A) && isequal(A[i+k], A[i])
k += 1
end
k
end
"""
RepVal(A)
Iterator generating the all (repeat length, value)-tuples in `A`.
"""
struct RepVal{T} A::T end
Base.IteratorSize(::Type{RepVal{T}}) where T = Base.SizeUnknown()
Base.eltype(x::RepVal) = Tuple{Int, eltype(x.A)} # (rep.len., value)
Base.iterate(x::RepVal) = iterate(x, firstindex(x.A))
function Base.iterate(x::RepVal, i::Int)
i > lastindex(x.A) && return nothing
k = repeatlength(x.A, i)
(k, x.A[i]), i + k
end
Input:
A = [1, 2, 3, 3, 3, 1, 1, 1, NaN, NaN, NaN, 2, 2, 3]
@show A
RepVal(A) |> collect
Output:
A = [1.0, 2.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, NaN, NaN, NaN, 2.0, 2.0, 3.0]
7-element Vector{Tuple{Int64, Float64}}:
(1, 1.0)
(1, 2.0)
(3, 3.0)
(3, 1.0)
(3, NaN)
(2, 2.0)
(1, 3.0)
Input:
maxrep_maxval(A) = maximum(RepVal(A))
maxrep_maxval(A)
Output:
(3, NaN)
Input:
negrep((k, v)) = (-k, v)
maxrep_minval(A) = negrep(minimum(negrep, RepVal(A)))
maxrep_minval(A)
Output:
(3, 1.0)
The iterator RepVal(A)
itself is very useful. We would do well to try to write types and functions that can be used as generic components.
For details of how to create an iterator, see Interfaces · The Julia Language.
Postscript 1: My interpretation of the problem is different from others. But this is also supposed to be helpful, so I’ll leave it at that.
Postscript 2: My minmode(X)
function:
using StatsBase
swap_negrep((val, rep)) = (-rep, val)
inv_swap_negrep((rep, val)) = (val, -rep)
minmode(X) = inv_swap_negrep(minimum(swap_negrep, countmap(X)))
This uses the lexicographic ordering of tuples, the same trick as above.