1
struct TimeArrayIterator{T, S}
2
    source::S
3
end
4

5 0
IteratorInterfaceExtensions.isiterable(x::TimeSeries.TimeArray) = true
6 0
TableTraits.isiterabletable(x::TimeSeries.TimeArray) = true
7

8
function IteratorInterfaceExtensions.getiterator(ta::S) where {S<:TimeSeries.TimeArray}
9 0
    etype = eltype(TimeSeries.values(ta))
10
    
11 0
    T = NamedTuple{(:timestamp, Symbol.(TimeSeries.colnames(ta))...), Tuple{S.parameters[3], fill(etype, length(TimeSeries.colnames(ta)))...}}
12

13 0
    return TimeArrayIterator{T, S}(ta)
14
end
15

16
function Base.length(iter::TimeArrayIterator)
17 0
    return length(iter.source)
18
end
19

20
function Base.eltype(iter::TimeArrayIterator{T,TS}) where {T,TS}
21 0
    return T
22
end
23

24 0
Base.eltype(::Type{TimeArrayIterator{T,TS}}) where {T,TS} = T
25

26
@generated function Base.iterate(iter::TimeArrayIterator{T,TS}, state=1) where {T,TS}
27 0
    constructor_call = Expr(:call, :($T))
28

29 0
    push!(constructor_call.args, Expr(:tuple))
30

31
    # Add timestamp column
32 0
    push!(constructor_call.args[2].args, :(TimeSeries.timestamp(iter.source)[i]))
33

34 0
    for i in 1:fieldcount(T)-1
35 0
        push!(constructor_call.args[2].args, :(TimeSeries.values(iter.source)[i,$i]))
36
    end
37

38 0
    quote
39 0
        if state>length(TimeSeries.timestamp(iter.source))
40 0
            return nothing
41
        else
42 0
            i = state
43 0
            a = $constructor_call
44 0
            return a, state+1
45
        end
46
    end
47
end
48

49
# Sink
50

51
function TimeSeries.TimeArray(x; timestamp_column::Symbol=:timestamp)
52 0
    TableTraits.isiterabletable(x) || error("Cannot create a TimeArray from something that is not a table.")
53

54 0
    iter = IteratorInterfaceExtensions.getiterator(x)
55

56 0
    et = eltype(iter)
57
    
58 0
    if fieldcount(et)<2
59 0
        error("Need at least two columns")
60
    end
61

62 0
    names = fieldnames(et)
63
    
64 0
    timestep_col_index = findfirst(isequal(timestamp_column), names)
65

66 0
    if timestep_col_index===nothing
67 0
        error("No timestamp column found.")
68
    end
69

70 0
    timestep_col_index = something(timestep_col_index)
71
    
72 0
    col_types = [fieldtype(et, i) for i=1:fieldcount(et)]
73

74 0
    data_columns = collect(Iterators.filter(i->i[2][1]!=timestamp_column, enumerate(zip(names, col_types))))
75

76 0
    orig_data_type = data_columns[1][2][2]
77

78 0
    data_type = orig_data_type <: DataValues.DataValue ? orig_data_type.parameters[1] : orig_data_type
79

80 0
    orig_timestep_type = col_types[timestep_col_index]
81

82 0
    timestep_type = orig_timestep_type <: DataValues.DataValue ? orig_timestep_type.parameters[1] : orig_timestep_type
83

84 0
    if any(i->i[2][2]!=orig_data_type, data_columns)
85 0
        error("All data columns need to be of the same type.")
86
    end
87

88 0
    t_column = Vector{timestep_type}(undef,0)
89 0
    d_array = Vector{Vector{data_type}}(undef,0)
90 0
    for i in data_columns
91 0
        push!(d_array, Vector{data_type}(undef,0))
92
    end
93

94 0
    for v in iter
95 0
        if orig_timestep_type <: DataValue
96 0
            push!(t_column, get(v[timestep_col_index]))
97
        else
98 0
            push!(t_column, v[timestep_col_index])
99
        end
100

101 0
        if orig_data_type <: DataValue
102 0
            for (i,c) in enumerate(data_columns)
103 0
                push!(d_array[i],get(v[c[1]]))
104
            end
105
        else
106 0
            for (i,c) in enumerate(data_columns)
107 0
                push!(d_array[i],v[c[1]])
108
            end
109
        end
110
    end
111

112 0
    d_array = hcat(d_array...)
113

114 0
    ta = TimeSeries.TimeArray(t_column,d_array,[i[2][1] for i in data_columns])
115 0
    return ta
116
end

Read our documentation on viewing source code .

Loading