Skip to content

Commit

Permalink
Merge pull request #11 from Arkoniak/arrays
Browse files Browse the repository at this point in the history
WIP: some basic array operations
  • Loading branch information
Arkoniak committed Apr 7, 2021
2 parents 691e501 + a29808d commit a44f8b8
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 51 deletions.
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ version = "0.1.0"

[deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"

[compat]
julia = "1"
Tables = "1"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand Down
8 changes: 5 additions & 3 deletions src/Timestamps.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
module Timestamps

using Dates

import Base: show
import Dates: month, year, day, value
import Base: show, size, getindex, push!, isempty
import Tables
# import Base: getindex, show, convert, sum, prod, mean, var, std, maximum, minimum, merge

include("timestamp.jl")
include("timestamparrays.jl")
include("tables.jl")
include("conversion.jl")
include("operators.jl")
include("arraymethods.jl")
include("utils.jl")

export Timestamp, TimestampArray
Expand Down
14 changes: 0 additions & 14 deletions src/arraymethods.jl

This file was deleted.

50 changes: 19 additions & 31 deletions src/operators.jl
Original file line number Diff line number Diff line change
@@ -1,41 +1,29 @@
# mathematical operators between two Timestamp objects
# for op in [:+, :-, :*, :/]
# @eval begin
# function ($op)(ts1::Timestamp, ts2::Timestamp)
# tstamp = abs(ts1.timestamp - ts2.timestamp)
# vals = ($op)(ts1.value, ts2.value)
# Timestamp(tstamp, vals)
# end # function
# end # eval
# end # loop
for op in [:(Base.:+), :(Base.:-), :(Base.:*), :(Base.:/)]
@eval begin
function ($op)(ts1::Timestamp, ts2::Timestamp)
vals = ($op).(ts1.val, ts2.val)
Timestamp(ts1.ts, vals)
end # function
end # eval
end # loop

# mathematical operators between a Timestamp object and Int,Float64
# for op in [:+, :-, :*, :/]
# @eval begin
# function ($op)(ts1::Timestamp, num::Union(Int,Float64))
# vals = ($op)(ts1.value, num)
# Timestamp(ts1.timestamp, vals)
# end # function
# end # eval
# end # loop
# mathematical operators between a Timestamp object and Number
for op in [:(Base.:+), :(Base.:-), :(Base.:*), :(Base.:/)]
@eval begin
function ($op)(ts1::Timestamp, num::Number)
vals = ($op).(ts1.val, num)
Timestamp(ts1.ts, vals)
end # function
end # eval
end # loop

# comparison operators between two Timestamp objects
#for op in [:>, :<, :==, :>=, :<=]
for op in [:(>), :(<), :(>=), :(<=), :(==)]
for op in [:(Base.:>), :(Base.:<), :(Base.:>=), :(Base.:<=), :(Base.isless)]
@eval begin
function ($op)(ts1::Timestamp, ts2::Timestamp)
function ($op)(ts1::Timestamp{D, T1}, ts2::Timestamp{D, T2}) where {D, T1, T2}
($op)(ts1.ts, ts2.ts)
end # function
end # eval
end # loop

# comparison operators between a Timestamp object and Int,Float64
#for op in [:>, :<, :==, :>=, :<=]
# for op in [:>, :<, :>=, :<=]
# @eval begin
# function ($op)(ts1::Timestamp, num::Union(Int,Float64))
# vals = ($op)(ts1.value, num)
# Timestamp(ts1.timestamp, vals)
# end # function
# end # eval
# end # loop
74 changes: 74 additions & 0 deletions src/tables.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
struct TimestampArrayTableRowsIterator{D, T, TP}
m::TimestampArray{D, T}
names::TP
end

Base.length(m::TimestampArrayTableRowsIterator) = length(m.m.tsps)
function Base.iterate(m::TimestampArrayTableRowsIterator, i = 1)
i > length(m) && return nothing
tsp = @inbounds m.m.tsps[i]
return (NamedTuple{m.names}((tsp.ts, tsp.val...)), i+1)
end

struct TimestampArrayTableColsIterator{D, T}
mapping::Dict{Symbol, Int}
m::TimestampArray{D, T}
end

function Base.iterate(m::TimestampArrayTableColsIterator, i = 1)
i > length(m.m.names) + 1 && return nothing
return (Tables.getcolumn(m, i), i+1)
end

Tables.istable(::Type{<:TimestampArray}) = true
Tables.columnnames(m::TimestampArray) = (:timestamp, m.names...)
Tables.rowaccess(::Type{<:TimestampArray}) = true
Tables.rows(m::TimestampArray) = TimestampArrayTableRowsIterator(m, Tables.columnnames(m))
Tables.columnaccess(::Type{<:TimestampArray}) = true
Tables.columns(m::TimestampArray) = TimestampArrayTableColsIterator(Dict(:timestamp => 1, (m.names .=> 2:length(m.names)+1)...), m)
Tables.schema(m::TimestampArray) = Tables.Schema((:timestamp, m.names...), nothing)
Tables.schema(m::TimestampArray{D, T}) where {D, T <: Tuple} = Tables.Schema((:timestamp, m.names...), Tuple{D, T.types...})
Tables.schema(m::TimestampArrayTableRowsIterator) = Tables.schema(m.m)

function Tables.getcolumn(m::TimestampArray{D, T}, i::Int) where {D, T <: Tuple}
i == 1 && return map(x -> x.ts, m.tsps)
return map(x -> x.val[i - 1], m.tsps)
end
function Tables.getcolumn(m::TimestampArray, nm::Symbol) where {D, T <: Tuple}
nm == :timestamp && return map(x -> x.ts, m.tsps)
i = findfirst(==(nm), m.names)
return map(x -> x.val[i], m.tsps)
end

Tables.columnnames(mci::TimestampArrayTableColsIterator) = Tables.columnnames(mci.m)
Tables.getcolumn(mci::TimestampArrayTableColsIterator, i::Int) = Tables.getcolumn(mci.m, i)
Tables.getcolumn(mci::TimestampArrayTableColsIterator, nm::Symbol) = Tables.getcolumn(mci.m, mci.mapping[nm])

########################################
# Constructor
########################################

# Ok, this one is experimental and probably should be moved to a different package
istimetable(::T) where T = istimetable(T)
istimetable(::Type{T}) where T = false
istimetable(::Type{<:TimestampArray}) = true
timeaxis(x::TimestampArray) = :timestamp

function TimestampArray(x; timestamp = :timestamp)
names = Tables.columnnames(x)
tscol = istimetable(x) ? timeaxis(x) : timestamp # fallback
indx = Vector{Int}(undef, length(names) - 1)
k = 0
for (i, nm) in pairs(names)
nm == tscol && continue
k += 1
indx[k] = i
end
rows = Tables.rows(x)
tsps = map(rows) do row
rt = ntuple(i -> row[indx[i]], length(row) - 1)
Timestamp(getproperty(row, tscol), rt)
end

return TimestampArray(tsps, names[indx])
end
8 changes: 5 additions & 3 deletions src/timestamp.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
abstract type AbstractTimestamp end

struct Timestamp{D, T} <: AbstractTimestamp
struct Timestamp{D, T} <: Dates.AbstractTime
ts::D
val::T
end
Expand All @@ -9,7 +7,11 @@ function Base.show(io::IO, ts::Timestamp)
print(io, ts.ts, " | ", ts.val)
end

Dates.month(ts::Timestamp) = month(ts.ts)
Dates.year(ts::Timestamp) = year(ts.ts)
Dates.day(ts::Timestamp) = day(ts.ts)

# Should use something like AxisKeys.jl or NamedDims.jl
# single date

# function getindex(tsa::TimestampArray, d::TimeType)
Expand Down
28 changes: 28 additions & 0 deletions src/timestamparrays.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
struct TimestampArray{D, T} <: AbstractVector{Timestamp{D, T}}
tsps::Vector{Timestamp{D, T}}
names::Vector{Symbol}
TimestampArray(v::AbstractVector{Timestamp{D, T}}, names) where {D, T} = new{D, T}(sort!(v), names)
end

size(tsparr::TimestampArray, i) = size(tsparr)[i]
size(tsparr::TimestampArray) = (length(tsparr.tsps), length(tsparr.names))

@Base.propagate_inbounds getindex(tsparr::TimestampArray, i::Integer) = getindex(tsparr.tsps, i)
@Base.propagate_inbounds getindex(tsparr::TimestampArray, r::AbstractUnitRange) = TimestampArray(getindex(tsparr.tsps, r), tsparr.names)

Base.isempty(v::TimestampArray) = isempty(v.tsps)

function Base.push!(v::TimestampArray{D, T}, tsp::Timestamp{D, T}) where {D, T}
if isempty(v)
push!(v.tsps, tsp)
elseif v[end] <= tsp
push!(v.tsps, tsp)
elseif v[1] >= tsp
pushfirst!(v.tsps, tsp)
else
push!(v.tsps, tsp)
sort!(v.tsps)
end

return v
end

2 comments on commit a44f8b8

@Arkoniak
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error while trying to register: "Tag with name v0.1.0 already exists and points to a different commit"

Please sign in to comment.