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

如何用openpyxl合并Excel中相同日期关联的多个ID

问题

我正在用openpyxl编写程序,读取Excel文件并生成新文件,将所有数据按正确顺序和格式整理。需求是从原文件的同一行中提取若干日期,在新文件里为每个日期生成一行,但当存在多个相同日期时,要把对应ID放在同一行。

日期和ID由另一个函数返回,格式如下:

l = [(ID1, date1), (ID2, date2), (ID3, date3)] 

举个例子,如果输入是:

l = [(ID1, 20160101), (ID2, 20180101), (ID3, 20160101)]

期望输出的Excel行是:

  • 第1行:20160101 - ID1, ID3
  • 第2行:20180101 - ID2

我目前的代码会给每个日期(哪怕重复)都生成新行,代码如下:

def gestRid(fimport, fimpianto):

    for i in range(2, fimport.max_row + 1):

        if dateRid(fimpianto, i):

            for tupla in dateRid(fimpianto, i):

                cod, data = tupla

                ultima_riga = fimport.max_row + 1 # ultima_riga == last_row

                for j in range(1, fimport.max_column + 1):

                    #Copies row at the end of worksheet
                    fimport.cell(row = ultima_riga, column = j).value = fimport.cell(row = i, column = j).value 
                
                fimport.cell(row = ultima_riga, column = 101).value = fimport.cell(row = i, column = 101).value + 1
                fimport.cell(row = ultima_riga, column = 1).value = fimport.cell(row = ultima_riga - 1, column = 1).value + 1
                fimport.cell(row = i, column = 46).value = (datetime.strptime(str(data), '%Y%m%d').date() - timedelta(days = 1)).strftime('%d/%m/%Y')
                fimport.cell(row = ultima_riga, column = 45).value = datetime.strptime(str(data), '%Y%m%d').strftime('%d/%m/%Y')
                fimport.cell(row = ultima_riga, column = 48).value = fimport.cell(row = ultima_riga, column = 45).value[6:]

                #Copies id in the first free cell
                if not fimport.cell(row = ultima_riga, column = 78).value:
                    fimport.cell(row = ultima_riga, column = 78).value = cod
                elif not fimport.cell(row = ultima_riga, column = 82).value:
                    fimport.cell(row = ultima_riga, column = 82).value = cod
                else:
                    fimport.cell(row = ultima_riga, column = 86).value = cod
最优实现方法

核心思路是先按日期分组收集ID,再根据分组结果生成Excel行,避免重复创建行。

步骤1:按日期分组ID

用字典存储日期和对应的ID列表,遍历dateRid返回的元组列表,把相同日期的ID归到同一组:

from collections import defaultdict

# 处理当前行的日期和ID,按日期分组
date_id_map = defaultdict(list)
for tupla in dateRid(fimpianto, i):
    cod, data = tupla
    date_id_map[data].append(cod)

这样date_id_map的结构为{日期: [ID1, ID2,...]},示例中会生成{20160101: [ID1, ID3], 20180101: [ID2]}。

步骤2:根据分组生成Excel行

遍历分组后的字典,为每个日期生成一行,并把该日期下的所有ID填入对应单元格:

def gestRid(fimport, fimpianto):
    from collections import defaultdict
    from datetime import datetime, timedelta

    for i in range(2, fimport.max_row + 1):
        tupla_list = dateRid(fimpianto, i)
        if not tupla_list:
            continue
        
        # 按日期分组ID
        date_id_map = defaultdict(list)
        for tupla in tupla_list:
            cod, data = tupla
            date_id_map[data].append(cod)
        
        # 遍历分组,生成行
        for data, cod_list in date_id_map.items():
            ultima_riga = fimport.max_row + 1
            # 复制原行数据到新行
            for j in range(1, fimport.max_column + 1):
                fimport.cell(row=ultima_riga, column=j).value = fimport.cell(row=i, column=j).value
            
            # 更新行的特定字段
            fimport.cell(row=ultima_riga, column=101).value = fimport.cell(row=i, column=101).value + 1
            fimport.cell(row=ultima_riga, column=1).value = fimport.cell(row=ultima_riga - 1, column=1).value + 1
            # 处理日期格式
            date_obj = datetime.strptime(str(data), '%Y%m%d').date()
            fimport.cell(row=i, column=46).value = (date_obj - timedelta(days=1)).strftime('%d/%m/%Y')
            fimport.cell(row=ultima_riga, column=45).value = date_obj.strftime('%d/%m/%Y')
            fimport.cell(row=ultima_riga, column=48).value = date_obj.strftime('%Y')  # 直接取年份,避免切片出错
            
            # 把多个ID填入对应单元格
            for idx, cod in enumerate(cod_list):
                if idx == 0:
                    fimport.cell(row=ultima_riga, column=78).value = cod
                elif idx == 1:
                    fimport.cell(row=ultima_riga, column=82).value = cod
                elif idx == 2:
                    fimport.cell(row=ultima_riga, column=86).value = cod
                # 若ID超过3个,可扩展列或拼接成字符串
                else:
                    existing = fimport.cell(row=ultima_riga, column=78).value or ""
                    fimport.cell(row=ultima_riga, column=78).value = f"{existing}, {cod}"

关键改进点

  1. 减少重复调用:将dateRid(fimpianto, i)的结果存入变量,避免循环内重复调用提升性能。
  2. 分组逻辑替代逐元组处理:每个日期仅生成一行,彻底解决重复日期多生成行的问题。
  3. ID填充更清晰:遍历ID列表依次填充对应列,超过数量时可灵活处理(如字符串拼接)。
  4. 日期处理更可靠:用strftime('%Y')直接获取年份,替代原代码中容易出错的切片操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 19:15:31