遍历Excel电子表格中的行并找出不同列中的值为零时的时间差

问题描述 投票:0回答:1

此代码迭代 Excel 电子表格并找到能量为零的特定列,然后通过计算连续零值的第一次和最后一次出现之间的差异来计算该零能量值周期的持续时间。

我遇到的问题是:当有多个连续的零行时,代码会停止并且永远不会提供输出。

我发现很难确定问题出在哪里。我可以得到一些帮助吗? 这是 Excel 文件中的示例数据。问题是当我们有超过几行零时如何获取输出。注意:实际 Excel 文件中的能量位于第 11 列,开始日期位于第 3 列,结束日期位于第 5 列,如代码所示。

开始日期 结束日期 能源
2023/1/1 10:54 2023/1/1 11:56 60
2023/1/1 13:28 2023/1/1 13:35 0
2023/1/1 19:02 2023/1/1 19:30 0
2023/1/1 21:03 2023/1/1 21:20 0
2023年1月1日21:35 2023/1/1 21:56 0
2023/1/1 22:23 2023/1/1 22:25 0
2023/1/2 08:34 2023/1/2 08:56 0
2023/1/2 09:04 2023/1/1 09:16 0
2023/1/2 09:14 2023/1/2 09:23 0
2023年1月2日10:05 2023/1/2 10:17 53

import datetime
import openpyxl
import collections
from itertools import islice

#import pandas
from openpyxl.workbook import Workbook

cpsd = ("Excel file")
cpsd_op = openpyxl.load_workbook(cpsd)
cpsd_s1 = cpsd_op['Session-2024']
cpsd_dcfc1 = openpyxl.Workbook()
sheet_dcfc1 = cpsd_dcfc1["Sheet"]

# ^ pulls excel file in, we want to use openpyxl over pandas for excel, since it takes less time
# cpsd = session data

max_col_og = cpsd_s1.max_column
max_row_og = cpsd_s1.max_row
max_col_nw = sheet_dcfc1.max_column
max_row_nw = sheet_dcfc1.max_row
print(max_row_og, max_col_og)

for i in range(1, max_col_og+1):
    c = cpsd_s1.cell(row = 1, column= i)
    sheet_dcfc1.cell(row=1, column=i).value = c.value


for i in range(1, max_col_og+1):
        cell_obj = sheet_dcfc1.cell(row=1, column=i)
        print(cell_obj.value)

def del_empt_row (sheet):
    index_row = []
    for i in range(1, sheet.max_row):
        # define emptiness of cell
        if sheet.cell(i, 1).value is None:
            # collect indexes of rows
            index_row.append(i)

    # loop each index value
    for row_del in range(len(index_row)):
        sheet.delete_rows(idx=index_row[row_del], amount=1)
        # exclude offset of rows through each iteration
        index_row = list(map(lambda k: k - 1, index_row))


for j in range(1, max_row_og +1):
    for i in range(1, max_col_og +1):
        c = cpsd_s1.cell(row=j, column=1)
        if (c.value == "PP/ Charger 2"):
            k = cpsd_s1.cell(row=j, column=i)
            sheet_dcfc1.cell(row=j, column=i).value = k.value
            #print(k.value)

del_empt_row(sheet_dcfc1)

def enddate (sheet, row):
    #returns the end date of the last row with energy = 0
    for row2 in range(row, max_row_og + 1):
        if (sheet.cell(row=row2, column=10).value != 0):
            return [sheet.cell(row=row2-1, column=5).value,row2-1]
        else:
            enddate(sheet,row+1)

def consume(iterator, n):
    #allows us to skip the energy = 0 rows that have already been counted, since python is weird about iteration skipping
    #"Advance the iterator n-steps ahead. If n is none, consume entirely."
    # Use functions that consume iterators at C speed.
    if n is None:
        # feed the entire iterator into a zero-length deque
        collections.deque(iterator, maxlen=0)
    else:
        # advance to the empty slice starting at position n
        next(islice(iterator, n, n), None)


zero_time = datetime.datetime(2023, 1, 1, 00, 00, 00, 00)
tot_time = datetime.datetime(2023, 1, 1, 00, 00, 00, 00)
#print(tot_time)

range_x = enumerate(sheet_dcfc1.iter_rows())
for row_num, row in range_x:
# calculates total time for t-outage provided that there are no empty rows.
    print(row_num)
    if (row[9].value == 0):
        strt_date = row[2].value
        print(strt_date)
        strt_row = row_num
        end_date_arr = enddate(sheet_dcfc1,row_num+1)
        end_date = end_date_arr[0]
        print(end_date)
        time = end_date-strt_date
        consume(range_x, end_date_arr[1]-strt_row)
#        print(row_num)
        #print(str(row) + "does row change?")
        tot_time += time

#        print(time)

print(tot_time-zero_time)
# prints total time for t-outage provided that there are no empty rows.

python excel function loops python-datetime
1个回答
0
投票

在代码中包含一些注释来解释每个部分的作用会很有帮助。但据我所知,您正在将原始工作簿中的标题添加到新工作簿中(然后阅读/打印这些标题)。

然后有一个循环寻找值为“PP/ Charger 2”的单元格
您的帖子中没有提到这一点,也没有在提供的表格中。而且循环也是错误的。

for j in range(1, max_row_og +1):
    for i in range(1, max_col_og +1):
        c = cpsd_s1.cell(row=j, column=1)
        if (c.value == "PP/ Charger 2"):
            k = cpsd_s1.cell(row=j, column=i)
            sheet_dcfc1.cell(row=j, column=i).value = k.value

您设置 j 来计算原始工作表中的行数,设置 i 来计算列数,然后

c = cpsd_s1.cell(row=j, column=1)
。所以这意味着它总是在同一列 (A) 中查找,“column=1”。想必这应该是“column=i”
如果更改此设置,那么您现在正在查看从 A1 到 K11 的每个单元格。这个值“PP/ Charger 2”是否会随机出现在任何列中,包括您显示的列?如果预计它位于特定列中,那么您应该仅迭代该列而不是整个使用的范围。请提供有关此值的内容/地点/时间的详细信息,因为它的存在对于下一节似乎很重要。如果没有它,新工作表将只包含标题。

如果上一节确实找到“PP/ Charger 2”值,则会将该值复制到新工作表中的“相同”单元格中。然后,代码运行删除操作,其目的是删除空行,假设“PP/ Charger 2”可能位于任何行上。虽然此删除实现了它,但它也删除了之前写入的标头。如果只需在原始工作表中每次出现时将该值写入页面一次,则可以使用 Openpyxl“追加”,以便每个值都将写入下一个未使用的行。无论哪种方式,都可以将值逐行添加到新工作表中,而无需删除空行。确切的实现将取决于预期在哪里找到此文本。 然后代码循环所有行中所有单元格的列表,专门在第 9 行中查找 0 值,

row[9].value == 0):

大概这是在寻找能量栏中的 0 值。但是,您声明 
Energy 位于第 11 列
或“K”列,而行[9] 位于“J”列。但为什么要选择整个范围而不是只循环 K 列呢? 然后代码寻找 0 值,但这是新的 Sheet range_x = enumerate(sheet_dcfc1.iter_rows())
,“sheet_dcfc1”,您写入的只是标题和值“PP/ Charger 2”(当它出现时)。没有值为 0 的单元格... 我似乎可能是当您找到值“PP/ Charger 2”时,您想要复制的整行而不仅仅是该单元格。
您需要更好地解释您的代码应该做什么,预期结果应该是什么。

© www.soinside.com 2019 - 2024. All rights reserved.