diff --git a/Project.toml b/Project.toml index 1119ae9..4d4a9fa 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Tables" uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" authors = ["quinnj "] -version = "1.7.0" +version = "1.8.0" [deps] DataAPI = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" diff --git a/docs/src/index.md b/docs/src/index.md index 50e066f..f649c80 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -277,6 +277,8 @@ matrix(m::MatrixTable) = getfield(m, :matrix) lookup(m::MatrixTable) = getfield(m, :lookup) # schema is column names and types Tables.schema(m::MatrixTable{T}) where {T} = Tables.Schema(names(m), fill(eltype(T), size(mat(m), 2))) +Tables.ncol(m::MatrixTable) = size(m.matrix, 2) +Tables.nrow(m::MatrixTable) = size(m.matrix, 1) ``` Here we defined `Tables.istable` for all `MatrixTable` types, signaling that they implement the Tables.jl interfaces. diff --git a/src/Tables.jl b/src/Tables.jl index 6f39462..7ac7978 100644 --- a/src/Tables.jl +++ b/src/Tables.jl @@ -32,6 +32,7 @@ Interface definition: | `Tables.columnnames(table)` | propertynames(table) | Return column names for a table as an indexable collection | | **Optional methods** | | | | `Tables.getcolumn(table, ::Type{T}, i::Int, nm::Symbol)` | Tables.getcolumn(table, nm) | Given a column eltype `T`, index `i`, and column name `nm`, retrieve the column. Provides a type-stable or even constant-prop-able mechanism for efficiency. | +| `Tables.ncol(table)` | Tables.ncol(table) | Return the number of columns | Note that subtypes of `Tables.AbstractColumns` **must** overload all required methods listed above instead of relying on these methods' default definitions. @@ -65,6 +66,7 @@ Interface definition: | `Tables.columnnames(row)` | propertynames(row) | Return column names for a row as an indexable collection | | **Optional methods** | | | | `Tables.getcolumn(row, ::Type{T}, i::Int, nm::Symbol)` | Tables.getcolumn(row, nm) | Given a column element type `T`, index `i`, and column name `nm`, retrieve the column value. Provides a type-stable or even constant-prop-able mechanism for efficiency. | +| `Tables.ncol(row)` | length(propertynames(row) | Return number of columns | Note that subtypes of `Tables.AbstractRow` **must** overload all required methods listed above instead of relying on these methods' default definitions. @@ -413,6 +415,23 @@ See also [`rowtable`](@ref) and [`namedtupleiterator`](@ref). """ function rows end +""" + nrow(cols::AbstractColumns) + +Returns the number of rows in an object that satisfies the `AbstractColumns` interface +as returned from `Tables.columns(tbl)`. Note that this isn't valid to call on _any_ valid +Tables.jl source as row-oriented tables may not have a defined length. +""" +function nrow end + +""" + ncol(rows::AbstractRows) + +Returns the number of columns in an object that satisfies the `AbstractRows` interface +as returned from `Tables.rows(tbl)`. +""" +function ncol end + # Schema implementation """ Tables.Schema(names, types) diff --git a/src/dicts.jl b/src/dicts.jl index 292adb8..79fb96e 100644 --- a/src/dicts.jl +++ b/src/dicts.jl @@ -93,6 +93,7 @@ schema(x::DictColumnTable) = getfield(x, :schema) columnnames(x::DictColumnTable) = getfield(x, :schema).names getcolumn(x::DictColumnTable, i::Int) = getfield(x, :values)[columnnames(x)[i]] getcolumn(x::DictColumnTable, nm::Symbol) = getfield(x, :values)[nm] +ncol(x::DictColumnTable) = length(columnnames(x)) struct DictRowTable names::Vector{Symbol} @@ -111,6 +112,7 @@ end columnnames(x::DictRow) = getfield(x, :names) getcolumn(x::DictRow, i::Int) = get(getfield(x, :row), columnnames(x)[i], missing) getcolumn(x::DictRow, nm::Symbol) = get(getfield(x, :row), nm, missing) +ncol(x::DictRow) = length(columnnames(x)) Base.IteratorSize(::Type{DictRowTable}) = Base.HasLength() Base.length(x::DictRowTable) = length(getfield(x, :values)) diff --git a/src/fallbacks.jl b/src/fallbacks.jl index 485b1ca..0e668df 100644 --- a/src/fallbacks.jl +++ b/src/fallbacks.jl @@ -5,6 +5,7 @@ # Turn any AbstractColumns into an AbstractRow iterator # get the number of rows in the incoming table +# this function is internal function rowcount(cols) names = columnnames(cols) isempty(names) && return 0 @@ -241,6 +242,7 @@ getcolumn(x::CopiedColumns, ::Type{T}, col::Int, nm::Symbol) where {T} = getcolu getcolumn(x::CopiedColumns, i::Int) = getcolumn(source(x), i) getcolumn(x::CopiedColumns, nm::Symbol) = getcolumn(source(x), nm) columnnames(x::CopiedColumns) = columnnames(source(x)) +ncol(x::CopiedColumns) = length(columnnames(x)) # here's our generic fallback Tables.columns definition @inline function columns(x::T) where {T} diff --git a/src/matrix.jl b/src/matrix.jl index 81e8482..8e5ec1f 100644 --- a/src/matrix.jl +++ b/src/matrix.jl @@ -41,6 +41,8 @@ columnnames(m::MatrixRow) = names(getfield(m, :source)) schema(m::MatrixTables{T}) where {T} = Schema(Tuple(names(m)), NTuple{size(getfield(m, :matrix), 2), eltype(T)}) Base.eltype(m::MatrixRowTable{T}) where {T} = MatrixRow{T} Base.length(m::MatrixRowTable) = size(getfield(m, :matrix), 1) +ncol(m::MatrixTable) = size(getfield(m, :matrix), 2) +nrow(m::MatrixTable) = size(getfield(m, :matrix), 1) Base.iterate(m::MatrixRowTable, st=1) = st > length(m) ? nothing : (MatrixRow(st, m), st + 1) diff --git a/src/namedtuples.jl b/src/namedtuples.jl index 7b2f3e5..00a4eca 100644 --- a/src/namedtuples.jl +++ b/src/namedtuples.jl @@ -108,7 +108,7 @@ end # NamedTuple of arrays of matching dimensionality const ColumnTable = NamedTuple{names, T} where {names, T <: NTuple{N, AbstractArray{S, D} where S}} where {N, D} -rowcount(c::ColumnTable) = length(c) == 0 ? 0 : length(c[1]) +nrow(c::ColumnTable) = length(c) == 0 ? 0 : length(c[1]) # interface implementation istable(::Type{<:ColumnTable}) = true diff --git a/test/runtests.jl b/test/runtests.jl index 88e5874..0e0a4a7 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -261,6 +261,8 @@ Tables.schema(x::MockTable) = Tables.Schema((:a, :b, :c), NTuple{3, Int}) @test Tables.getcolumn(matrow, :Column1) == 1 @test Tables.getcolumn(matrow, 1) == 1 @test propertynames(mattbl) == propertynames(matrow) == [:Column1, :Column2, :Column3] + @test Tables.nrow(mattbl) == 3 + @test Tables.ncol(mattbl) == 3 mattbl = Tables.table(mat, header=[:A, :B, :C]) @test Tables.columnnames(mattbl) == [:A, :B, :C]