You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

火车行程分组算法需求:基于最多31天连续时段的桶式分组

火车行程分组算法设计方案

针对你提出的全年火车出行数据分组需求——将含日期、金额(单日多笔)的记录分组到最多覆盖31个连续自然日的桶中,我整理了一套实用的实现思路和方案:

核心需求拆解

首先明确几个关键约束:

  • 每个桶的时间范围是连续31个自然日以内(允许不足31天)
  • 单日多笔行程记录需全部归入对应日期所在的桶
  • 所有行程记录必须被覆盖,且每个记录仅属于一个桶

基础实现思路(无额外优化目标)

如果只是需要完成基础的分组覆盖,不需要平衡桶的金额或其他指标,最直接的方式是按自然日滑动分段,步骤如下:

1. 数据预处理

  • 先将所有行程记录按日期升序排序,确保时间顺序正确
  • 统一日期格式(推荐YYYY-MM-DD),避免排序或比较出错
  • 可选:构建「日期→对应所有行程记录」的映射表(比如用Python的defaultdict(list)),后续分组时能快速定位对应日期的记录,提升效率

2. 分段分组逻辑

从最早的行程日期开始,每次取最长的连续31天自然日作为一个桶的时间范围,将该范围内的所有行程记录归入桶中,再从下一个未覆盖的日期重复此操作:

  • 确定当前桶的起始日期,计算其往后推30天的日期(即31个连续自然日的结束日期)
  • 收集所有日期在「起始日期→结束日期」范围内的行程记录,组成一个桶
  • 若剩余未分组的日期不足31天,直接将剩余所有记录归入最后一个桶

伪代码示例(Python)

from datetime import datetime, timedelta
from collections import defaultdict

def group_train_trips(trips, max_continuous_days=31):
    # 预处理:按日期排序并构建日期-行程映射
    sorted_trips = sorted(trips, key=lambda x: x[0])
    if not sorted_trips:
        return []
    
    date_to_trips = defaultdict(list)
    for trip in sorted_trips:
        date_to_trips[trip[0]].append(trip)
    
    # 获取所有有行程的日期并排序
    all_dates = sorted(date_to_trips.keys())
    buckets = []
    current_pos = 0
    total_dates = len(all_dates)
    
    while current_pos < total_dates:
        # 计算当前桶的时间范围:31个连续自然日
        start_date_str = all_dates[current_pos]
        start_dt = datetime.strptime(start_date_str, "%Y-%m-%d")
        end_dt = start_dt + timedelta(days=max_continuous_days - 1)
        end_date_str = end_dt.strftime("%Y-%m-%d")
        
        # 找到当前桶覆盖的最后一个有行程的日期索引
        end_pos = current_pos
        while end_pos < total_dates and all_dates[end_pos] <= end_date_str:
            end_pos += 1
        
        # 收集当前桶的所有行程记录
        bucket_records = []
        for date in all_dates[current_pos:end_pos]:
            bucket_records.extend(date_to_trips[date])
        
        # 计算桶的统计信息(可选)
        total_amount = sum(trip[1] for trip in bucket_records)
        buckets.append({
            "date_range": f"{start_date_str} ~ {all_dates[end_pos-1]}",
            "actual_days_with_trips": end_pos - current_pos,
            "total_trips": len(bucket_records),
            "total_amount": round(total_amount, 2),
            "trips": bucket_records
        })
        
        current_pos = end_pos
    
    return buckets

# 测试用例
sample_trips = [
    ("2024-01-01", 50),
    ("2024-01-01", 30),
    ("2024-01-15", 45),
    ("2024-02-02", 60),
    ("2024-02-28", 70)
]
print(group_train_trips(sample_trips))

进阶优化:平衡桶的金额分布

如果你的需求不仅是分组,还希望每个桶的总金额尽量均衡(比如避免某个桶金额过高),可以采用动态规划的思路:

  • 定义dp[i]为前i个有行程的日期分组后的最优代价(比如总金额的方差、最大桶金额等)
  • 转移方程:dp[i] = min(dp[j] + cost(j+1, i)),其中j的取值范围是max(0, i-31)i-1cost(j+1,i)表示将第j+1i个日期的行程归入一个桶的代价
  • 通过遍历所有可能的分段点,找到代价最小的分组方式

注意事项

  • 日期处理要注意跨月、跨年的情况,使用标准日期库(如Python的datetime)避免手动计算出错
  • 若数据量极大(百万级以上),可以考虑用批量处理或数据库查询(比如SQL的窗口函数)来提升效率,避免内存瓶颈

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

火山引擎 最新活动