Repository: JuliaData/Tables.jl (julia)

Issue:
adding Tables.table methods
@quinnj would you be OK to allow `AbstracVector{Symbol}` and `AbstractVector{<:AbstractString}` as a `header` in `Tables.table`.

relevant for a decision in https://github.com/JuliaData/DataFrames.jl/issues/2433#issuecomment-695050438.

Pull request description:
Fixes https://github.com/JuliaData/Tables.jl/issues/199

Patch:
diff --git a/src/matrix.jl b/src/matrix.jl
index 744190f..11a3591 100644
--- a/src/matrix.jl
+++ b/src/matrix.jl
@@ -43,17 +43,21 @@ getcolumn(m::MatrixTable, i::Int) = getfield(m, :matrix)[:, i]
 columnnames(m::MatrixTable) = names(m)
 
 """
-    Tables.table(m::AbstractMatrix; [header::Vector{Symbol}])
+    Tables.table(m::AbstractMatrix; [header])
 
-Wrap an `AbstractMatrix` (`Matrix`, `Adjoint`, etc.) in a `MatrixTable`, which satisfies
-the Tables.jl interface. This allows accesing the matrix via `Tables.rows` and
-`Tables.columns`. An optional keyword argument `header` can be passed as a `Vector{Symbol}`
-to be used as the column names. Note that no copy of the `AbstractMatrix` is made.
+Wrap an `AbstractMatrix` (`Matrix`, `Adjoint`, etc.) in a `MatrixTable`, which satisfies the
+Tables.jl interface. This allows accessing the matrix via `Tables.rows` and `Tables.columns`.
+An optional keyword argument iterator `header` can be passed which will be converted to a
+`Vector{Symbol}` to be used as the column names. Note that no copy of the `AbstractMatrix`
+is made, but `header` is always stored as freshly allocated object.
 """
-function table(m::AbstractMatrix; header::Vector{Symbol}=[Symbol("Column$i") for i = 1:size(m, 2)])
-    length(header) == size(m, 2) || throw(ArgumentError("provided column names `header` length must match number of columns in matrix ($(size(m, 2)))"))
-    lookup = Dict(nm=>i for (i, nm) in enumerate(header))
-    return MatrixTable(header, lookup, m)
+function table(m::AbstractMatrix; header=[Symbol("Column$i") for i = 1:size(m, 2)])
+    symbol_header = [Symbol(h) for h in header]
+    if length(symbol_header) != size(m, 2)
+        throw(ArgumentError("provided column names `header` length must match number of columns in matrix ($(size(m, 2)))"))
+    end
+    lookup = Dict(nm=>i for (i, nm) in enumerate(symbol_header))
+    return MatrixTable(symbol_header, lookup, m)
 end
 
 """


Test patch:
diff --git a/test/runtests.jl b/test/runtests.jl
index 83a6dae..885551c 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -240,6 +240,16 @@ end
     @test Tables.getcolumn(matrow, 1) == 1
     @test propertynames(mattbl) == propertynames(matrow) == [:Column1, :Column2, :Column3]
 
+    mattbl = Tables.table(mat, header=[:A, :B, :C])
+    @test Tables.columnnames(mattbl) == [:A, :B, :C]
+    mattbl = Tables.table(mat, header=view(["DUMMY", "A", "B", "C"], 2:4))
+    @test Tables.columnnames(mattbl) == [:A, :B, :C]
+    mattbl = Tables.table(mat, header=(["DUMMY", "A", "B", "C"][i] for i in 2:4))
+    @test Tables.columnnames(mattbl) == [:A, :B, :C]
+    mattbl = Tables.table(mat, header=1:3)
+    @test Tables.columnnames(mattbl) == Symbol.(1:3)
+    @test_throws ArgumentError Tables.table(mat, header=[:A, :B, :C, :D])
+
     # #155
     m = hcat([1,2,3],[1,2,3])
     T = Tables.table(m)