2015-12-02 2 views
1

Мне нужно найти лист Excel для ячеек, содержащих некоторый шаблон. Это занимает больше времени, чем я могу справиться. Самый оптимизированный код, который я мог бы написать, приведен ниже. Поскольку шаблоны данных обычно являются строками за строкой, поэтому я использую iter_rows (row_offset = x). К сожалению, приведенный ниже код находит данный шаблон все чаще в каждом для цикла (начиная с миллисекунды и доходя до почти минуты). Что я делаю не так?Openpyxl оптимизация скорости поиска ячеек

import openpyxl 
import datetime 
from openpyxl import Workbook 

wb = Workbook() 
ws = wb.active 
ws.title = "test_sheet" 

print("Generating quite big excel file") 

for i in range(1,10000): 
    for j in range(1,20): 
     ws.cell(row = i, column = j).value = "Cell[{},{}]".format(i,j) 

print("Saving test excel file") 
wb.save('test.xlsx') 

def FindXlCell(search_str, last_r): 
    t = datetime.datetime.utcnow() 
    for row in ws.iter_rows(row_offset=last_r): 
     for cell in row: 
      if (search_str == cell.value): 
       print(search_str, last_r, cell.row, datetime.datetime.utcnow() - t) 
       last_r = cell.row 
       return last_r 
    print("record not found ",search_str, datetime.datetime.utcnow() - t) 
    return 1 

wb = openpyxl.load_workbook("test.xlsx", data_only=True) 
t = datetime.datetime.utcnow() 
ws = wb["test_sheet"] 
last_row = 1 
print("Parsing excel file in a loop for 3 cells") 
for i in range(1,100,1): 
    last_row = FindXlCell("Cell[0,0]", last_row) 
    last_row = FindXlCell("Cell[1000,6]", last_row) 
    last_row = FindXlCell("Cell[6000,6]", last_row) 

ответ

3

Зацикливание на листе несколько раз неэффективно. Причина постепенного замедления поиска заключается в том, что в каждом цикле становится все больше памяти. Это связано с тем, что last_row = FindXlCell("Cell[0,0]", last_row) означает, что следующий поиск будет создавать новые ячейки в конце строк: openpyxl создает ячейки по требованию, потому что строки могут быть технически пустыми, но ячейки в них по-прежнему адресуемы. В конце вашего сценария рабочий лист имеет в общей сложности 598000 строк, но вы всегда начинаете поиск с A1.

Если вы хотите найти большой файл для текста несколько раз, тогда, вероятно, было бы разумно создать матрицу с ключом по тексту с координатами, являющимися значением.

Что-то вроде:

matrix = {} 
for row in ws: 
    for cell in row: 
     matrix[cell.value] = (cell.row, cell.col_idx) 

В реальном мире, например, вы, вероятно, хотите использовать defaultdict, чтобы иметь возможность обрабатывать несколько ячеек с одинаковым текстом.

Это может быть объединено с режимом только для чтения для минимального объема памяти. За исключением, конечно, если вы хотите отредактировать файл.

Смежные вопросы