2014-01-15 3 views
2

У меня очень большой список, и мне нужно запустить много поисков для этого списка. Чтобы быть более конкретным, я работаю над большим текстовым файлом (> 11 Гб) для обработки, но есть элементы, которые появляются более одного раза, и я только обрабатываю их сначала, когда они появляются. Если шаблон появляется, я обрабатываю его и помещаю его в список. Если элемент появляется снова, я проверяю его в списке, и если это так, то я просто передать на обработку, например:Ускорить поиск элемента в списке (через Python)

[...] 
if boundary.match(line): 
    if closedreg.match(logentry): 
     closedthreads.append(threadid) 
    elif threadid in closedthreads: 
     pass 
    else: 
[...] 

сам код далек от оптимального. Моя основная проблема заключается в том, что список «closedthreads» содержит несколько миллионов элементов, и вся операция только начинает замедляться и замедляться. Я думаю, что это может помочь сортировать список (или использовать объект отсортированного списка) после каждого append(), но я не уверен в этом. Какое самое элегантное решение?

+0

Как уже указывалось в ответах, было бы полезно узнать больше о «threadid»: какой тип он есть, если значения каким-то образом ограничены ... в конце вам понадобится быстрый поиск, следовательно, хеширование и в некоторых случаях создание собственной хеш-функции может быть способом; знание домена помогает там. – mknecht

+0

Threadid - простое целое число. (Я обрабатываю много файлов mysql_slow.log, чтобы повторно запускать их на серверах с воспроизведением percona. Чтобы ускорить процесс воспроизведения, мне нужно закрыть потоки, которые появляются последними в журналах. – banyek

+0

Тогда принятый ответ, скорее всего, сделайте все правильно. Если у вас все еще есть проблемы с скоростью, тогда пришло время более внимательно рассмотреть эти цифры. Или, скорее, решить проблему по-другому. :) – mknecht

ответ

2

Использование набора вместо списка даст вам время поиска O (1), хотя могут быть другие способы оптимизации, которые будут лучше работать для ваших конкретных данных.

closedthreads = set() 
# ... 

if boundary.match(line): 
    if closedreg.match(logentry): 
     closedthreads.add(threadid) 
    elif threadid in closedthreads: 
     pass 
    else: 
+0

Спасибо за пример. (Я принял другой ответ, потому что он был быстрее.) – banyek

+0

:(извините, dude, в следующий раз – banyek

3

Вы можете просто использовать набор или хеш-таблицу, которая отмечает, если данный идентификатор уже появился. Он должен решить вашу проблему с временной сложностью O (1) для добавления и поиска элемента.

1

Нужно сохранить заказ?

Если нет - используйте комплект.

Если вы это сделаете - используйте OrderedDict. OrderedDict также позволяет хранить связанные с ним значения (например, результаты процесса)

Но ... вам нужно сохранить исходные значения вообще? Вы можете посмотреть модуль «dbm», если вы абсолютно это сделаете (или купите много памяти!) Или вместо хранения фактического текста храните SHA-1 дайджесты или что-то в этом роде. Если все, что вы хотите сделать, это убедиться, что вы не запускаете один и тот же элемент дважды, это может сработать.

+0

Я бы предположил, что идентификатор потока, вероятно, короче, чем его SHA1 хэш (хотя OP не дает достаточной информации) , и что сама операция хеширования будет слишком дорогостоящей вычислительной. – geoffspear

+0

Да, это правда - по какой-то причине я думал, что исходные элементы были строками. В этом случае это может быть не так уж и медленнее, и может даже быть быстрее (так как для проверки того, находится ли элемент в наборе, вы должны вызывать как '__hash__', так и' __eq__', а равенство строк не обязательно мало влияет на длинные строки) .... –

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