Форум сайта python.su
Ну питон - это не си++, и разбиение кода на более мелкие элементарные части в обход конструкциям питона только увеличивает время исполнения (зачастую). Конечно, нельзя утверждать, что последний вариант однозначно быстрее любого предложенного другого, пока не измеришь (к тому же это ничего не стоит), но уже интуитивно видно, что скорее всего это так.
Отредактировано (Дек. 6, 2010 11:15:19)
Офлайн
Isem, мне интересны подобные задачки. Спецы начинают изобретать, как лучше.
Было бы хорошо еще и таки измерять скорость - если об этом речь.
Насколько быстрее?
Стоит скорость того?
К месту или нет?
Может, задачка вообще не предполагает гонку за микросекундами?
К слову, в С++ часто код выполняется дольше, чем в аналогичном С для конкретного случая. И, тем не менее, я люблю мудреные плюсы с перегруженной частичной типизацией шаблонов - особенно если применяется к месту.
Офлайн
Вообще эта задача близка к достаточно общей задаче list partitioning. В Эрланге, например, есть lists:partition: http://www.erlang.org/doc/man/lists.html#partition-2, в Хаскеле тоже: http://zvon.org/other/haskell/Outputlist/partition_f.html
К сожалению исторически так сложилось, что более развитый аппарат работы со списками присущ функциональным языкам более, чем таким, как Питон.
На мой взгляд наиболее правильным было бы решение с использованием аналога partitioning, что нибудь типа такого:
result = [], res
for v in val:
result[bool_func(v)].append(v)
vals, res = result
Офлайн
Тем не менее, отличие самого медленного от самого быстрого составляет 2 раза. Для “тяжелой” bool_func, отличие будет конечно более заметно.
import time
import random
def bool_func( v ):
return bool(v & 1)
def func1( vals, res ):
res += [v for v in vals if bool_func(v)]
vals = [v for v in vals if not bool_func(v)]
return vals
def func2( vals, res ):
tmp = [(v, bool_func(v)) for v in vals]
res += [v[0] for v in tmp if v[1]]
vals = [v[0] for v in tmp if not v[1]]
return vals
def func3( vals, res ):
tmp = []
for v in vals:
if bool_func(v):
res.append(v)
else:
tmp.append(v)
vals = tmp
return vals
def func4( vals, res ):
vals = [v for v in vals if (res.append(v) if bool_func(v) else True)]
return vals
def func5( vals, res ):
vals = [v for v in vals if not bool_func(v) or res.append(v)]
return vals
def func6( vals, res ):
result = [], res
for v in vals:
result[bool_func(v)].append(v)
return result[0]
vals = list(range(100000))
random.shuffle( vals )
for func in [func1, func2, func3, func4, func5, func6]:
start = time.clock()
for i in range(20):
res = []
func( vals, res )
print( "Time for {} = {}".format( func.__name__, (time.clock() - start)/20 ) )
Офлайн
Только потому, что самый медленный вариант - двухпроходный.
Отличие хакерского варианта 5 и варианта ‘в лоб’ 3 несущественно, на мой взгляд.
Офлайн
Но если “легкую” функцию bool_func сделать inline, то есть явно переписать ее содержимое в цикле вместо вызова, то скорость еще удвоится. Так что опять приходим к тяжелой для питона ноше - вызову функций.
То есть в нашем тестовом случае это:
vals = [v for v in vals if not (v&1) or res.append(v)]
Офлайн