You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为包装向量的Series实现时间范围索引的存取方法

实现Series结构体的日期时间范围索引方法

首先假设你的Series结构体定义包含日期时间戳向量和数据矩阵,并且已经实现了AbstractArray的基础接口(比如size):

using Dates

mutable struct Series{T<:Real} <: AbstractArray{T,2}
    timestamps::Vector{DateTime}
    data::Matrix{T}
end

# 实现AbstractArray的必要接口:返回尺寸
Base.size(s::Series) = size(s.data)

# 可选:实现默认整数索引的getindex
Base.getindex(s::Series, i::Int, j::Int) = s.data[i,j]
Base.getindex(s::Series, i::Union{Int,AbstractArray}, j::Union{Int,AbstractArray}) = s.data[i,j]

1. 实现Getter方法(getindex)

支持series[startDateTime:endDateTime, :]的索引访问,核心是找到时间戳落在目标范围内的行索引,再返回对应的子Series:

高效版本(适用于已排序的时间戳)

如果timestamps是升序排列的,用searchsortedfirst和searchsortedlast快速定位索引范围,避免遍历所有元素:

# 处理单位日期时间范围(start:end)
function Base.getindex(s::Series, dt_range::UnitRange{DateTime}, ::Colon)
    start_idx = searchsortedfirst(s.timestamps, first(dt_range))
    end_idx = searchsortedlast(s.timestamps, last(dt_range))
    Series(s.timestamps[start_idx:end_idx], s.data[start_idx:end_idx, :])
end

# 处理带步长的日期时间范围(比如 start:Hour(1):end)
function Base.getindex(s::Series, dt_range::StepRange{DateTime,<:Period}, ::Colon)
    base_idx = searchsortedfirst(s.timestamps, first(dt_range)):searchsortedlast(s.timestamps, last(dt_range))
    filtered_timestamps = s.timestamps[base_idx]
    match_idx = findall(t -> t in dt_range, filtered_timestamps)
    final_idx = base_idx[match_idx]
    Series(filtered_timestamps[match_idx], s.data[final_idx, :])
end

通用版本(适用于任意顺序的时间戳)

如果时间戳未排序,遍历所有元素筛选符合条件的行:

function Base.getindex(s::Series, dt_range::Union{UnitRange{DateTime}, StepRange{DateTime,<:Period}}, ::Colon)
    idx = findall(t -> first(dt_range) ≤ t ≤ last(dt_range), s.timestamps)
    # 带步长的范围额外验证时间戳是否匹配步长规则
    if dt_range isa StepRange
        idx = idx[findall(i -> s.timestamps[i] in dt_range, idx)]
    end
    Series(s.timestamps[idx], s.data[idx, :])
end

2. 实现Setter方法(setindex!)

支持对日期时间范围的行进行赋值操作,先定位目标索引再修改数据矩阵:

数组赋值

function Base.setindex!(s::Series, value::AbstractArray, dt_range::Union{UnitRange{DateTime}, StepRange{DateTime,<:Period}}, ::Colon)
    idx = if dt_range isa UnitRange
        searchsortedfirst(s.timestamps, first(dt_range)):searchsortedlast(s.timestamps, last(dt_range))
    else
        base_idx = searchsortedfirst(s.timestamps, first(dt_range)):searchsortedlast(s.timestamps, last(dt_range))
        base_idx[findall(i -> s.timestamps[i] in dt_range, base_idx)]
    end
    @assert size(value) == (length(idx), size(s,2)) "赋值数据尺寸与目标范围不匹配"
    s.data[idx, :] .= value
end

标量赋值

function Base.setindex!(s::Series, value::Real, dt_range::Union{UnitRange{DateTime}, StepRange{DateTime,<:Period}}, ::Colon)
    idx = if dt_range isa UnitRange
        searchsortedfirst(s.timestamps, first(dt_range)):searchsortedlast(s.timestamps, last(dt_range))
    else
        base_idx = searchsortedfirst(s.timestamps, first(dt_range)):searchsortedlast(s.timestamps, last(dt_range))
        base_idx[findall(i -> s.timestamps[i] in dt_range, base_idx)]
    end
    s.data[idx, :] .= value
end

关键注意事项

  • Series的timestamps字段必须存储每行对应的日期时间戳,这是范围选择的核心依据。
  • 若时间戳已排序,优先使用基于searchsorted的方法,能大幅提升索引效率。
  • 可根据需求扩展更多索引形式,比如单个日期时间点、部分列的选择等。

内容的提问来源于stack exchange,提问作者BAR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 22:20:26