Мой любимый рецепт для этого:
goodvals = set(goodvals) # Turbocharges the performance by 55%!
good, bad = [], []
_ = [good.append(x) if x in goodvals else bad.append(x) for x in mylist]
Простой, быстрый и читаемый; каким Python должен был быть.
- Делая
goodvals
в set
(который использует хеш-таблицу) вместо
tuple
, мы получаем супер быстрый поиск.
- Каждый элемент в
mylist
проверяется только
один раз. это помогает сделать это быстрее.
_ =
- это Pythonic способ заявить, что мы намеренно отбрасываем результат понимания списка. Это не ошибка.
(На основании комментария Дансалмо к этого ответа, потому что он, похоже, заслуживает своего собственного ответа.)
РЕДАКТИРОВАТЬ:
Преобразование goodvals
в установленную производительность турбокомпрессоров на 55% по моему тесту. Использование tuple
- это O (n * m), а преобразование его в set
- это O (log n + m).
Кроме того, goodvals
, (т.е. n), имеет длину всего пять элементов. mylist
, (т. Е. М), может иметь сотни предметов. Кроме того, создание набора, вероятно, высоко оптимизировано под капотом в коде языка C.
Вот код теста, который я использовал. Он основан на коде, взятом из этого ответа и изменен для работы с Python v3.7.0, работающим в Windows 7.
good_list = ['.jpg','.jpeg','.gif','.bmp','.png']
import random
import string
my_origin_list = []
for i in range(10000):
fname = ''.join(random.choice(string.ascii_lowercase) for i in range(random.randrange(10)))
if random.getrandbits(1):
fext = random.choice(list(good_list))
else:
fext = "." + ''.join(random.choice(string.ascii_lowercase) for i in range(3))
my_origin_list.append((fname + fext, random.randrange(1000), fext))
# Parand
def f1(*_):
return [e for e in my_origin_list if e[2] in good_list], [e for e in my_origin_list if not e[2] in good_list]
# dbr
def f2(*_):
a, b = list(), list()
for e in my_origin_list:
if e[2] in good_list:
a.append(e)
else:
b.append(e)
return a, b
# John La Rooy
def f3(*_):
a, b = list(), list()
for e in my_origin_list:
(b, a)[e[2] in good_list].append(e)
return a, b
# # Ants Aasma
# def f4():
# l1, l2 = tee((e[2] in good_list, e) for e in my_origin_list)
# return [i for p, i in l1 if p], [i for p, i in l2 if not p]
# My personal way to do
def f5(*_):
a, b = zip(*[(e, None) if e[2] in good_list else (None, e) for e in my_origin_list])
return list(filter(None, a)), list(filter(None, b))
# BJ Homer
def f6(*_):
return list(filter(lambda e: e[2] in good_list, my_origin_list)), list(filter(lambda e: not e[2] in good_list, my_origin_list))
# ChaimG's answer; as a list.
def f7(*_):
good, bad = [], []
for e in my_origin_list:
_ = good.append(e) if e[2] in good_list else bad.append(e)
return good, bad
# ChaimG's answer; as a set.
def f8(*_):
good, bad = [], []
good_list_set = set(good_list)
for e in my_origin_list:
_ = good.append(e) if e[2] in good_list_set else bad.append(e)
return good, bad
def cmpthese(n=0, functions=None):
results = {}
for func_name in functions:
args = ['%s(range(256))' % func_name, 'from __main__ import %s' % func_name]
t = Timer(*args)
results[func_name] = 1 / (t.timeit(number=n) / n) # passes/sec
functions_sorted = sorted(functions, key=results.__getitem__)
for f in functions_sorted:
diff = []
for func in functions_sorted:
if func == f:
diff.append(" --")
else:
diff.append("%5.0f%%" % (results[f]/results[func]*100 - 100))
diffs = " ".join(diff)
print("%s\t%6d/s %s" % (f, results[f], diffs))
if __name__=='__main__':
from timeit import Timer
cmpthese(1000, 'f1 f2 f3 f5 f6 f7 f8'.split(" "))