Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
Manifest.toml
Manifest.toml
.vscode
3 changes: 3 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,11 @@ the table-specific use-case, knowing that it will Just Work™️.
Before moving on to _implementing_ the Tables.jl interfaces, we take a quick
break to highlight some useful utility functions provided by Tables.jl:
```@docs
Tables.Schema
Tables.schema
Tables.getrows
Tables.partitions
Tables.partitioner
Tables.rowtable
Expand Down Expand Up @@ -239,6 +241,7 @@ For a type `MyTable`, the interface to becoming a proper table is straightforwar
| **Optional methods** | | |
| `Tables.schema(x::MyTable)` | `Tables.schema(x) = nothing` | Return a [`Tables.Schema`](@ref) object from your `Tables.AbstractRow` iterator or `Tables.AbstractColumns` object; or `nothing` for unknown schema |
| `Tables.materializer(::Type{MyTable})` | `Tables.columntable` | Declare a "materializer" sink function for your table type that can construct an instance of your type from any Tables.jl input |
| `Tables.getrows(x::MyTable, inds; view)` | | Return a row or a sub-table of the original table
Based on whether your table type has defined `Tables.rows` or `Tables.columns`, you then ensure that the `Tables.AbstractRow` iterator
or `Tables.AbstractColumns` object satisfies the respective interface.
Expand Down
23 changes: 23 additions & 0 deletions src/Tables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,29 @@ struct Partitioner{T}
x::T
end

"""
Tables.getrows(x, inds; view=nothing)

Return one or more rows from table `x` according to the position(s) specified by `inds`:

- If `inds` is a single integer return a row object.
- If `inds` is a collection of integers, return an indexable object of rows.
In this case, the returned type is not necessarily the same as the original table type.

The `view` argument influences whether the returned object is a view of the original table
or an independent copy:

- If `view=nothing` (the default) then the implementation for a specific table type
is free to decide whether to return a copy or a view.
- If `view=true` then a view is returned and if `view=false` a copy is returned.
This applies both to returning a row or a table.

Any specialized implementation of `getrows` must support the `view=nothing` argument.
Support for `view=true` or `view=false` is optional
(i.e. implementations might error on them if they are not supported).
"""
function getrows end

"""
Tables.partitioner(f, itr)
Tables.partitioner(x)
Expand Down
16 changes: 16 additions & 0 deletions src/namedtuples.jl
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ function rowtable(itr::T) where {T}
return collect(namedtupleiterator(eltype(r), r))
end

function getrows(x::RowTable, inds; view::Union{Bool,Nothing} = nothing)
if view === true
return Base.view(x, inds)
else
return x[inds]
end
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])
Expand Down Expand Up @@ -173,3 +181,11 @@ function columntable(itr::T) where {T}
return columntable(schema(cols), cols)
end
columntable(x::ColumnTable) = x

function getrows(x::ColumnTable, inds; view::Union{Bool,Nothing} = nothing)
if view === true
return map(c -> Base.view(c, inds), x)
else
return map(c -> c[inds], x)
end
end
29 changes: 29 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,34 @@ end
@test Tables.buildcolumns(nothing, rt) == nt
@test Tables.columntable(nothing, nt) == nt

@testset "columntable getrows" begin
@test Tables.getrows(nt, 1) == (a=1, b=4.0, c="7")
@test Tables.getrows(nt, 1, view=false) == (a=1, b=4.0, c="7")
@test Tables.getrows(nt, 1, view=nothing) == (a=1, b=4.0, c="7")
@test Tables.getrows(nt, 1:2) == (a=[1,2], b=[4.0, 5.0], c=["7","8"])
@test Tables.getrows(nt, 1:2, view=false) == (a=[1,2], b=[4.0, 5.0], c=["7","8"])
@test Tables.getrows(nt, 1:2, view=nothing) == (a=[1,2], b=[4.0, 5.0], c=["7","8"])

@test Tables.getrows(nt, 1, view=true) == (a = fill(1), b = fill(4.0), c = fill("7"))
rs = Tables.getrows(nt, 1:2, view=true)
@test rs == (a=[1,2], b=[4.0, 5.0], c=["7","8"])
@test rs.a.parent === nt.a
end

@testset "rowtable getrows" begin
@test Tables.getrows(rt, 1) == (a=1, b=4.0, c="7")
@test Tables.getrows(rt, 1, view=false) == (a=1, b=4.0, c="7")
@test Tables.getrows(rt, 1, view=nothing) == (a=1, b=4.0, c="7")
@test Tables.getrows(rt, 1:2) == [(a=1, b=4.0, c="7"), (a=2, b=5.0, c="8")]
@test Tables.getrows(rt, 1:2, view=false) == [(a=1, b=4.0, c="7"), (a=2, b=5.0, c="8")]
@test Tables.getrows(rt, 1:2, view=nothing) == [(a=1, b=4.0, c="7"), (a=2, b=5.0, c="8")]

@test Tables.getrows(rt, 1, view=true) == fill((a = 1, b = 4.0, c = "7"))
rs = Tables.getrows(rt, 1:2, view=true)
@test rs == [(a=1, b=4.0, c="7"), (a=2, b=5.0, c="8")]
@test rs.parent === rt
end

# test push!
rtf = Iterators.Filter(x->x.a >= 1, rt)
@test Tables.columntable(rtf) == nt
Expand Down Expand Up @@ -798,4 +826,5 @@ Tables.columnnames(::WideTable2) = [Symbol("x", i) for i = 1:1000]
@test nm isa Symbol
@test col isa Vector{Float64}
end

end