遍历Excel表格行,当另一列值为零时找出时间差
这段代码是用来处理一个Excel表格的,它会查找一个特定的列,看看能量值是否为零。如果找到了零值,它会计算这个零值持续的时间,也就是计算连续零值出现的第一次和最后一次之间的时间差。
我遇到的问题是:当有多行连续的零值时,代码就会卡住,根本没有输出结果。
我现在很难找到问题出在哪里。能不能帮我一下?这里是Excel文件中的示例数据。问题出在当有多行零值时,代码无法输出结果。注意:能量值在第11列,开始日期在第3列,结束日期在第5列,这些在实际的Excel文件中和代码里是一致的。
开始日期 | 结束日期 | 能量 |
---|---|---|
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.
1 个回答
在代码中加一些注释会很有帮助,这样可以解释每个部分的作用。
从我看到的代码来看,你首先是把原始表格 'Session-2024' 的标题添加到一个新的工作表 sheet_dcfc1
中,命名为 'Sheet'(然后再读取和打印这些标题)。
接下来是一个循环,寻找值为 "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 的 'append' 方法,这样每次都会写到下一个未使用的行。无论如何,这个值可以逐行添加到新表中,而不需要再删除空行。具体的实现取决于这个文本应该在哪里找到,以及应该如何写入新表。
接下来,代码会遍历所有行中的所有单元格,特别是在第9列查找值为0的单元格,row[9].value == 0):
这可能是在查找能源列中的0值。然而你提到过能源在第11列,也就是 K 列,而 row[9] 是 J 列。为什么不只遍历 K 列呢?
然后代码在寻找值为0,但这是在新表 range_x = enumerate(sheet_dcfc1.iter_rows())
中,而你写入的只有标题和 "PP/ Charger 2" 的值(如果出现的话),然后又删除了标题。新表中没有值为0的单元格……
看起来当你找到 "PP/ Charger 2" 时,你是想复制整行,而不仅仅是那个单元格?
你需要更清楚地解释你的代码应该做什么,预期的结果是什么。