< Summary

Information
Class: src/index.jl
Assembly: Default
File(s): src/index.jl
Tag: 61_25545638018
Line coverage
92%
Covered lines: 73
Uncovered lines: 6
Coverable lines: 79
Total lines: 135
Line coverage: 92.4%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

File(s)

src/index.jl

#LineLine coverage
 1# simplified form of https://github.com/JuliaData/DataFrames.jl/blob/master/src/other/index.jl
 2abstract type AbstractIndex end
 3
 4struct Index <: AbstractIndex   # an OrderedDict would be nice here...
 135    lookup::Dict{AbstractString, Int}      # name => names array position
 6    names::Vector{AbstractString}
 7end
 8
 129function Index(names::Array{T, 1}) where T <: AbstractString
 1310    @assert allunique(names) "names must be unique check for $names"
 1111    lookup = Dict{AbstractString, Int}(zip(names, 1:length(names)))
 1112    Index(lookup, names)
 13end
 14
 115Index() = Index(Dict{AbstractString, Int}(), String[])
 2316Base.length(x::Index) = length(x.names)
 1217Base.names(x::Index) = copy(x.names)
 918_names(x::Index) = x.names
 119Base.copy(x::Index) = Index(copy(x.lookup), copy(x.names))
 320Base.isequal(x::AbstractIndex, y::AbstractIndex) = _names(x) == _names(y) # it is enough to check names
 221Base.:(==)(x::AbstractIndex, y::AbstractIndex) = isequal(x, y)
 22
 623Base.haskey(x::Index, key::AbstractString) = haskey(x.lookup, key)
 424Base.haskey(x::Index, key::Integer) = 1 <= key <= length(x.names)
 125Base.haskey(x::Index, key::Bool) =
 26    throw(ArgumentError("invalid key: $key of type Bool"))
 227Base.keys(x::Index) = names(x)
 28
 129@inline Base.getindex(x::AbstractIndex, idx::Bool) = throw(ArgumentError("invalid index: $idx of type Bool"))
 30
 431@inline function Base.getindex(x::AbstractIndex, idx::Integer)
 432    if !(1 <= idx <= length(x))
 233        throw(BoundsError("attempt to access a Index with $(length(x)) columns at index $idx"))
 34    end
 235    Int(idx)
 36end
 37
 738@inline function Base.getindex(x::AbstractIndex, idx::AbstractVector{Int})
 739    isempty(idx) && return idx
 1240    minidx, maxidx = extrema(idx)
 641    if minidx < 1
 142        throw(BoundsError("attempt to access a Index with $(length(x)) columns at index $minidx"))
 43    end
 544    if maxidx > length(x)
 145        throw(BoundsError("attempt to access a Index with $(length(x)) columns at index $maxidx"))
 46    end
 447    allunique(idx) || throw(ArgumentError("Elements of $idx must be unique"))
 048    idx
 49end
 50
 551@inline function Base.getindex(x::AbstractIndex, idx::AbstractRange{Int})
 552    isempty(idx) && return idx
 453    minidx, maxidx = extrema(idx)
 454    if minidx < 1
 155        throw(BoundsError("attempt to access a Index with $(length(x)) columns at index $minidx"))
 56    end
 357    if maxidx > length(x)
 158        throw(BoundsError("attempt to access a Index with $(length(x)) columns at index $maxidx"))
 59    end
 260    allunique(idx) || throw(ArgumentError("Elements of $idx must be unique"))
 061    idx
 62end
 63
 064@inline Base.getindex(x::AbstractIndex, idx::AbstractRange{<:Integer}) = getindex(x, collect(Int, idx))
 165@inline Base.getindex(x::AbstractIndex, ::Colon) = Base.OneTo(length(x))
 66
 167@inline function Base.getindex(x::AbstractIndex, idx::AbstractVector{<:Integer})
 368    if any(v -> v isa Bool, idx)
 069        throw(ArgumentError("Bool values except for AbstractVector{Bool} are not allowed for column indexing"))
 70    end
 171    getindex(x, Vector{Int}(idx))
 72end
 73
 074@inline Base.getindex(x::AbstractIndex, idx::AbstractRange{Bool}) = getindex(x, collect(idx))
 75
 276@inline function Base.getindex(x::AbstractIndex, idx::AbstractVector{Bool})
 377    length(x) == length(idx) || throw(BoundsError(x, idx))
 178    findall(idx)
 79end
 80
 81# catch all method handling cases when type of idx is not narrowest possible, Any in particular
 682@inline function Base.getindex(x::AbstractIndex, idxs::AbstractVector)
 683    isempty(idxs) && return Int[] # special case of empty idxs
 584    if idxs[1] isa Real
 1085        if !all(v -> v isa Integer && !(v isa Bool), idxs)
 286            throw(ArgumentError("Only Integer values allowed when indexing by vector of numbers"))
 87        end
 188        return getindex(x, convert(Vector{Int}, idxs))
 89    end
 290    idxs[1] isa AbstractString && return getindex(x, convert(Vector{AbstractString}, idxs))
 191    throw(ArgumentError("idxs[1] has type $(typeof(idxs[1])); "*
 92                        "Only Integer or String values allowed when indexing by vector"))
 93end
 94
 395@inline function Base.getindex(x::AbstractIndex, rx::Regex)
 1596    getindex(x, filter(name -> occursin(rx, String(name)), _names(x)))
 97end
 98
 99"""
 100    fuzzymatch(l::Dict, idx::AbstractString)
 101# Fuzzy matching rules:
 102# 1. ignore case
 103# 2. maximum Levenshtein distance is 2
 104# 3. always show matches with 0 difference (wrong case)
 105# 4. on top of 3. do not show more than 8 matches in total
 106# Returns candidates ordered by (distance, name) pair
 107"""
 3108function fuzzymatch(l::Dict{AbstractString, Int}, idx::AbstractString)
 3109        idxs = uppercase(idx)
 3110        dist = [(REPL.levenshtein(uppercase(x), idxs), x) for x in keys(l)]
 3111        sort!(dist)
 39112        c = [count(x -> x[1] <= i, dist) for i in 0:2]
 3113        maxd = max(0, searchsortedlast(c, 8) - 1)
 3114        [s for (d, s) in dist if d <= maxd]
 115end
 116
 56117@inline function lookupname(l::Dict{AbstractString, Int}, idx::AbstractString)
 109118    i = get(l, idx, nothing)
 56119    if i === nothing
 3120        candidates = fuzzymatch(l, idx)
 3121        if isempty(candidates)
 2122            throw(ArgumentError("column name :$idx not found in the data frame"))
 123        end
 1124        candidatesstr = join(string.(':', candidates), ", ", " and ")
 1125        throw(ArgumentError("column name :$idx not found in the data frame; " *
 126                            "existing most similar names are: $candidatesstr"))
 127    end
 0128    i
 129end
 130
 89131@inline Base.getindex(x::Index, idx::AbstractString) = lookupname(x.lookup, idx)
 6132@inline function Base.getindex(x::Index, idx::AbstractVector{AbstractString})
 7133    allunique(idx) || throw(ArgumentError("Elements of $idx must be unique"))
 5134    [lookupname(x.lookup, i) for i in idx]
 135end

Methods/Properties