From 2ff4a604cd0d259f5f1a25d25279a5c43804a233 Mon Sep 17 00:00:00 2001 From: rikhuijzer Date: Wed, 29 Jun 2022 16:32:34 +0200 Subject: [PATCH 1/8] Add `columncount` --- Project.toml | 2 +- src/Tables.jl | 3 +-- src/fallbacks.jl | 7 ++++++- test/runtests.jl | 1 + 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Project.toml b/Project.toml index 1119ae9..893fe2a 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.7.1" [deps] DataAPI = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" diff --git a/src/Tables.jl b/src/Tables.jl index 6f39462..8b1e7bc 100644 --- a/src/Tables.jl +++ b/src/Tables.jl @@ -208,8 +208,7 @@ function Base.show(io::IO, x::T) where {T <: AbstractRow} end function Base.show(io::IO, table::AbstractColumns; max_cols = 20) - ncols = length(columnnames(table)) - print(io, "$(typeof(table)) with $(rowcount(table)) rows, $(ncols) columns, and ") + print(io, "$(typeof(table)) with $(rowcount(table)) rows, $(columncount(table)) columns, and ") sch = schema(table) if sch !== nothing print(io, "schema:\n") diff --git a/src/fallbacks.jl b/src/fallbacks.jl index 485b1ca..77c4f53 100644 --- a/src/fallbacks.jl +++ b/src/fallbacks.jl @@ -4,13 +4,18 @@ # Turn any AbstractColumns into an AbstractRow iterator -# get the number of rows in the incoming table +"Return the number of rows in the incoming table." function rowcount(cols) names = columnnames(cols) isempty(names) && return 0 return length(getcolumn(cols, names[1])) end +"Return the number of columns in the incoming table." +function columncount(cols) + return length(columnnames(cols)) +end + # a lazy row view into a AbstractColumns object struct ColumnsRow{T} <: AbstractRow columns::T # an `AbstractColumns`-compatible object diff --git a/test/runtests.jl b/test/runtests.jl index 88e5874..4585b38 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -133,6 +133,7 @@ end rt = [(a=1, b=4.0, c="7"), (a=2, b=5.0, c="8"), (a=3, b=6.0, c="9")] nt = (a=[1,2,3], b=[4.0, 5.0, 6.0], c=["7", "8", "9"]) @test Tables.rowcount(nt) == 3 + @test Tables.columncount(nt) == 3 @test Tables.schema(nt) == Tables.Schema((:a, :b, :c), Tuple{Int, Float64, String}) @test Tables.istable(typeof(nt)) @test Tables.columnaccess(typeof(nt)) From ccf71e0334e9829f18cecd6a8676e4e558ce8e50 Mon Sep 17 00:00:00 2001 From: rikhuijzer Date: Wed, 29 Jun 2022 17:17:34 +0200 Subject: [PATCH 2/8] Rename to `nrow` and `ncol` --- src/Tables.jl | 2 +- src/fallbacks.jl | 9 ++++----- src/matrix.jl | 2 +- src/namedtuples.jl | 2 +- test/runtests.jl | 5 +++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Tables.jl b/src/Tables.jl index 8b1e7bc..199920b 100644 --- a/src/Tables.jl +++ b/src/Tables.jl @@ -208,7 +208,7 @@ function Base.show(io::IO, x::T) where {T <: AbstractRow} end function Base.show(io::IO, table::AbstractColumns; max_cols = 20) - print(io, "$(typeof(table)) with $(rowcount(table)) rows, $(columncount(table)) columns, and ") + print(io, "$(typeof(table)) with $(nrow(table)) rows, $(ncol(table)) columns, and ") sch = schema(table) if sch !== nothing print(io, "schema:\n") diff --git a/src/fallbacks.jl b/src/fallbacks.jl index 77c4f53..c0fddb4 100644 --- a/src/fallbacks.jl +++ b/src/fallbacks.jl @@ -5,16 +5,15 @@ # Turn any AbstractColumns into an AbstractRow iterator "Return the number of rows in the incoming table." -function rowcount(cols) +function nrow(cols) names = columnnames(cols) isempty(names) && return 0 return length(getcolumn(cols, names[1])) end +@deprecate rowcount(x) nrow(x) "Return the number of columns in the incoming table." -function columncount(cols) - return length(columnnames(cols)) -end +ncol(cols) = length(columnnames(cols)) # a lazy row view into a AbstractColumns object struct ColumnsRow{T} <: AbstractRow @@ -91,7 +90,7 @@ function rows(x::T) where {T} # first check if it supports column access, and if so, wrap it in a RowIterator if columnaccess(x) cols = columns(x) - return RowIterator(cols, Int(rowcount(cols))) + return RowIterator(cols, Int(nrow(cols))) # otherwise, if the input is at least iterable, we'll wrap it in an IteratorWrapper # which will iterate the input, validating that elements support the AbstractRow interface # and unwrapping any DataValues that are encountered diff --git a/src/matrix.jl b/src/matrix.jl index 81e8482..8a732df 100644 --- a/src/matrix.jl +++ b/src/matrix.jl @@ -84,7 +84,7 @@ function matrix(table; transpose::Bool=false) cols = Columns(table) types = schema(cols).types T = reduce(promote_type, types) - n, p = rowcount(cols), length(types) + n, p = nrow(cols), length(types) if !transpose matrix = Matrix{T}(undef, n, p) for (i, col) in enumerate(cols) 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 4585b38..8f49230 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -132,8 +132,9 @@ end rt = [(a=1, b=4.0, c="7"), (a=2, b=5.0, c="8"), (a=3, b=6.0, c="9")] nt = (a=[1,2,3], b=[4.0, 5.0, 6.0], c=["7", "8", "9"]) - @test Tables.rowcount(nt) == 3 - @test Tables.columncount(nt) == 3 + @test_deprecated Tables.rowcount(nt) + @test Tables.nrow(nt) == 3 + @test Tables.ncol(nt) == 3 @test Tables.schema(nt) == Tables.Schema((:a, :b, :c), Tuple{Int, Float64, String}) @test Tables.istable(typeof(nt)) @test Tables.columnaccess(typeof(nt)) From 27c4c48266fbd2509d42b1a800561354e402242a Mon Sep 17 00:00:00 2001 From: Rik Huijzer Date: Thu, 30 Jun 2022 08:43:31 +0200 Subject: [PATCH 3/8] Apply suggestions from code review Co-authored-by: Jacob Quinn --- src/fallbacks.jl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/fallbacks.jl b/src/fallbacks.jl index c0fddb4..be557b3 100644 --- a/src/fallbacks.jl +++ b/src/fallbacks.jl @@ -4,7 +4,13 @@ # Turn any AbstractColumns into an AbstractRow iterator -"Return the number of rows in the incoming table." +""" + nrow(::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(cols) names = columnnames(cols) isempty(names) && return 0 From 57222568a587f1840ddd4216a3dbf9af4cbf474c Mon Sep 17 00:00:00 2001 From: rikhuijzer Date: Thu, 30 Jun 2022 09:29:29 +0200 Subject: [PATCH 4/8] Define nrow and ncol more selectively --- docs/src/index.md | 2 ++ src/Tables.jl | 22 +++++++++++++++++++++- src/dicts.jl | 2 ++ src/fallbacks.jl | 18 +++++------------- src/matrix.jl | 4 +++- test/runtests.jl | 6 +++--- 6 files changed, 36 insertions(+), 18 deletions(-) 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 199920b..c0fad26 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.ncols(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.ncols(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. @@ -208,7 +210,8 @@ function Base.show(io::IO, x::T) where {T <: AbstractRow} end function Base.show(io::IO, table::AbstractColumns; max_cols = 20) - print(io, "$(typeof(table)) with $(nrow(table)) rows, $(ncol(table)) columns, and ") + ncols = length(columnnames(table)) + print(io, "$(typeof(table)) with $(rowcount(table)) rows, $(ncols) columns, and ") sch = schema(table) if sch !== nothing print(io, "schema:\n") @@ -412,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..b7a66f1 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] +ncols(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 be557b3..0e668df 100644 --- a/src/fallbacks.jl +++ b/src/fallbacks.jl @@ -4,22 +4,13 @@ # Turn any AbstractColumns into an AbstractRow iterator -""" - nrow(::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(cols) +# get the number of rows in the incoming table +# this function is internal +function rowcount(cols) names = columnnames(cols) isempty(names) && return 0 return length(getcolumn(cols, names[1])) end -@deprecate rowcount(x) nrow(x) - -"Return the number of columns in the incoming table." -ncol(cols) = length(columnnames(cols)) # a lazy row view into a AbstractColumns object struct ColumnsRow{T} <: AbstractRow @@ -96,7 +87,7 @@ function rows(x::T) where {T} # first check if it supports column access, and if so, wrap it in a RowIterator if columnaccess(x) cols = columns(x) - return RowIterator(cols, Int(nrow(cols))) + return RowIterator(cols, Int(rowcount(cols))) # otherwise, if the input is at least iterable, we'll wrap it in an IteratorWrapper # which will iterate the input, validating that elements support the AbstractRow interface # and unwrapping any DataValues that are encountered @@ -251,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 8a732df..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) @@ -84,7 +86,7 @@ function matrix(table; transpose::Bool=false) cols = Columns(table) types = schema(cols).types T = reduce(promote_type, types) - n, p = nrow(cols), length(types) + n, p = rowcount(cols), length(types) if !transpose matrix = Matrix{T}(undef, n, p) for (i, col) in enumerate(cols) diff --git a/test/runtests.jl b/test/runtests.jl index 8f49230..0e0a4a7 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -132,9 +132,7 @@ end rt = [(a=1, b=4.0, c="7"), (a=2, b=5.0, c="8"), (a=3, b=6.0, c="9")] nt = (a=[1,2,3], b=[4.0, 5.0, 6.0], c=["7", "8", "9"]) - @test_deprecated Tables.rowcount(nt) - @test Tables.nrow(nt) == 3 - @test Tables.ncol(nt) == 3 + @test Tables.rowcount(nt) == 3 @test Tables.schema(nt) == Tables.Schema((:a, :b, :c), Tuple{Int, Float64, String}) @test Tables.istable(typeof(nt)) @test Tables.columnaccess(typeof(nt)) @@ -263,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] From 30ee986434f4c5caf134b89fc9fae0fb5a3a7722 Mon Sep 17 00:00:00 2001 From: Rik Huijzer Date: Thu, 30 Jun 2022 09:47:49 +0200 Subject: [PATCH 5/8] Change to minor version bump --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 893fe2a..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.1" +version = "1.8.0" [deps] DataAPI = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" From ca813861116e07c0a5ac043c91838f0896fb1b46 Mon Sep 17 00:00:00 2001 From: rikhuijzer Date: Thu, 30 Jun 2022 17:41:44 +0200 Subject: [PATCH 6/8] Rename ncols to ncol --- src/Tables.jl | 8 ++++---- src/dicts.jl | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Tables.jl b/src/Tables.jl index c0fad26..aed500d 100644 --- a/src/Tables.jl +++ b/src/Tables.jl @@ -32,7 +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.ncols(table)` | Tables.ncol(table) | Return the number of columns | +| `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. @@ -66,7 +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.ncols(row)` | length(propertynames(row) | Return number of columns | +| `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. @@ -210,8 +210,8 @@ function Base.show(io::IO, x::T) where {T <: AbstractRow} end function Base.show(io::IO, table::AbstractColumns; max_cols = 20) - ncols = length(columnnames(table)) - print(io, "$(typeof(table)) with $(rowcount(table)) rows, $(ncols) columns, and ") + ncol = length(columnnames(table)) + print(io, "$(typeof(table)) with $(rowcount(table)) rows, $(ncol) columns, and ") sch = schema(table) if sch !== nothing print(io, "schema:\n") diff --git a/src/dicts.jl b/src/dicts.jl index b7a66f1..79fb96e 100644 --- a/src/dicts.jl +++ b/src/dicts.jl @@ -93,7 +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] -ncols(x::DictColumnTable) = length(columnnames(x)) +ncol(x::DictColumnTable) = length(columnnames(x)) struct DictRowTable names::Vector{Symbol} From f094263e6f72e975ff5374e17aeff1a2a239827f Mon Sep 17 00:00:00 2001 From: rikhuijzer Date: Thu, 30 Jun 2022 17:42:30 +0200 Subject: [PATCH 7/8] Align table again --- src/Tables.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tables.jl b/src/Tables.jl index aed500d..e9b0934 100644 --- a/src/Tables.jl +++ b/src/Tables.jl @@ -32,7 +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 | +| `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. @@ -66,7 +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 | +| `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. From acc8ac85e6eb27ccc66baca74fab86f8bae562aa Mon Sep 17 00:00:00 2001 From: rikhuijzer Date: Mon, 4 Jul 2022 09:49:57 +0200 Subject: [PATCH 8/8] Small change --- src/Tables.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tables.jl b/src/Tables.jl index e9b0934..7ac7978 100644 --- a/src/Tables.jl +++ b/src/Tables.jl @@ -210,8 +210,8 @@ function Base.show(io::IO, x::T) where {T <: AbstractRow} end function Base.show(io::IO, table::AbstractColumns; max_cols = 20) - ncol = length(columnnames(table)) - print(io, "$(typeof(table)) with $(rowcount(table)) rows, $(ncol) columns, and ") + ncols = length(columnnames(table)) + print(io, "$(typeof(table)) with $(rowcount(table)) rows, $(ncols) columns, and ") sch = schema(table) if sch !== nothing print(io, "schema:\n")