簡體   English   中英

提高excel文件操作的速度(使用openpyxl):如果有條件檢查值和刪除行操作

[英]Increase the speed of an excel file operations (using openpyxl): check value and delete rows operations if condition

我有一個中等大小的 excel 文件,大約有 25000 行。

在 excel 文件中,我檢查特定列值是否在列表中,如果在列表中,我將刪除該行。

我正在使用 openpyxl。

編碼:

   count = 1
    while count <= ws.max_row:
        if ws.cell(row=count, column=2).value in remove_list:
            ws.delete_rows(count, 1)
        else:
            count += 1
    wb.save(src)

該代碼有效,但完成速度非常慢(需要數小時)。

我知道這是只讀和只寫模式,但在我的情況下,我同時使用,首先檢查和第二次刪除。

我看到您正在使用需要刪除的行列表。 相反,您可以創建要刪除的行的“序列”,從而將像 [2,3,4,5,6,7,8,45,46,47,48] 這樣的刪除列表更改為 [[2, 7] ],[45, 4]]

即從第 2 行開始刪除 7 行,然后從第 45 行開始刪除 4 行

批量刪除比 1 x 1 快。我在大約 10 秒內刪除了 6k 行

以下代碼將列表轉換為列表/序列列表:

def get_sequences(list_of_ints):
    sequence_count = 1
    sequences = []
    for row in list_of_ints:
        next_item = None
        if list_of_ints.index(row) < (len(list_of_ints) - 1):
            next_item = list_of_ints[list_of_ints.index(row) + 1]

        if (row + 1) == next_item:
            sequence_count += 1
        else:
            first_in_sequence = list_of_ints[list_of_ints.index(row) - sequence_count + 1]
            sequences.append([first_in_sequence, sequence_count])
            sequence_count = 1

    return sequences

然后運行另一個循環刪除

    for sequence in sequences:
        sheet.delete_rows(sequence[0], sequence[1])

就我個人而言,我會做兩件事:

首先將列表轉換為一個集合,以便查找項目花費更少的時間

remove_set = set(remove_list)
...
if ws.cell(row=count, column=2).value in remove_set:

然后我會避免刪除原地的行,因為重新組織表示工作表的數據結構需要很多時間。

我會創建一個新的空白工作表,並只添加必須保留的行。

然后保存新工作表,如果您願意,可以覆蓋原始工作表。

如果仍然需要太長時間,請考慮使用 CSV 格式,以便您可以將輸入數據視為文本並以相同方式輸出,稍后從電子表格程序(例如 Ms-Excel)重新導入數據

查看官方文檔本教程以了解如何使用 CSV 庫

進一步注意:正如@Charlie Clark 所發現的那樣,計算

ws.max_row

也可能需要一些時間,無需重復。

要做到這一點,最簡單的解決方案是從最后一行倒退到第一行,這樣被刪除的行就不會影響它們前面的行的位置。

當必須從工作表中刪除許多行時,我創建這些行號的列表,例如remove_list ,然后將工作表重寫為臨時工作表,不包括這些行。 我刪除原始工作表並將臨時工作表重命名為原始工作表。 請參閱我在下面執行此操作的功能:

def delete_excel_rows_with_openpyxl(workbook, sheet, remove_list): 
    """ Delete rows with row numbers in remove_list from sheet contained in workbook """ 

    temp_sheet = workbook.create_sheet('TempSheet')

    destination_row_counter = 1
    for source_row_counter, source_row in enumerate(sheet.iter_rows(min_row=1, max_row=sheet.max_row)):

        try:
            i = remove_list.index(source_row_counter+1) # enumerate counts from 0 and sheet from 1
            # do not copy row
            del remove_list[i]
        except ValueError:
            # copy row
            column_count = 1
            for cell in source_row:
                temp_sheet.cell(row=destination_row_counter, column=column_count).value = cell.value
                column_count = column_count + 1

            destination_row_counter = destination_row_counter + 1

    sheet_title = sheet.title
    workbook.remove_sheet(sheet)
    temp_sheet.title = sheet_title

    return workbook, temp_sheet   

添加到 ketdaddy 的回復中。 我對其進行了測試,並注意到當您按照建議在 for 循環中使用此序列時,您需要更新每個循環中的行號以說明已刪除的行。

例如,當您到達循環的第二步時,起始行不是原始起始行,而是原始起始行減去先前刪除的行。

此代碼將更新 ketdaddy 的序列以生成考慮到這一點的序列。

original sequence = get_sequences(deleterows)
updated_sequence=[]
cumdelete = 0
for start, delete in original sequence:
    new_start = start-cumdelete
    cumdelete = cumdelete + delete
    updated_sequence.append([new_start, delete])

updated_sequence

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM