Я пытался применить алгоритм для сокращения списка Python в меньший на основе определенные критерии. Из-за большого объема исходного списка, в порядке 100k элементов, я попробовал к itertools за предотвращение нескольких выделений памяти, таким образом, я придумал это:
reducedVec = [ 'F' if sum( 1 for x in islice(vec, i, i+ratio) if x == 'F' )
> ratio / 3.0 else 'T'
for i in xrange(0, len(vec), ratio) ]
Время выполнения для этого тревожно занимает много времени в порядке нескольких минут, когда vec имеет вокруг 100k элементов. Когда я попробовал вместо этого:
reducedVec = [ 'F' if sum( 1 for x in vec[i:i+ratio] if x == 'F' )
> ratio / 3.0 else 'T'
for i in xrange(0, len(vec), ratio) ]
в сущности замените islice частью, выполнение мгновенно.
Можно ли думать о вероятном объяснении этого? Я думал бы, что то, чтобы не неоднократно выделить новый список со значительным числом элементов, на самом деле сохранит меня несколько вычислительных циклов вместо того, чтобы нанести вред целому выполнению.
С наилучшими пожеланиями, Фемида
islice
работает с произвольными итерациями. Для этого, вместо того, чтобы сразу переходить к n-му элементу, он должен просмотреть первые n-1, отбрасывая их, а затем выдать нужные вам элементы.
Посмотрите чистую реализацию на Python из документации itertools:
def islice(iterable, *args):
# islice('ABCDEFG', 2) --> A B
# islice('ABCDEFG', 2, 4) --> C D
# islice('ABCDEFG', 2, None) --> C D E F G
# islice('ABCDEFG', 0, None, 2) --> A C E G
s = slice(*args)
it = iter(xrange(s.start or 0, s.stop or sys.maxint, s.step or 1))
nexti = next(it)
for i, element in enumerate(iterable):
if i == nexti:
yield element
nexti = next(it)
Говоря о документации itertools, если бы я пытался выполнить эту операцию, я бы, вероятно, использовал рецепт grouper
. На самом деле он не сэкономит вам память, но мог бы, если бы вы переписали его так, чтобы он был более ленивым, что было бы несложно.
from __future__ import division
from itertools import izip_longest
def grouper(n, iterable, fillvalue=None):
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
reducedVec = []
for chunk in grouper(ratio, vec):
if sum(1 for x in chunk if x == 'F') > ratio / 3:
reducedVec.append('F')
else:
reducedVec.append('T')
Мне нравится использовать grouper
, чтобы абстрагироваться от последовательных кусочков, и я нахожу этот код гораздо более легким для чтения, чем оригинальный
Я предполагаю, что использование islice ()
включает вызов функции Python для каждого элемента vec
, в то время как расширенная нотация среза понимается парсером и преобразуется непосредственно в вызовы CPython.