Форум сайта python.su
857
vic57Да, а можно один раз пройти. Если там миллион элементов в списке, а сам код вызывается 10000 раз, это имеет значение. Поэтому стараются всегда писать однопроходные коды. У них сложность O(n), тогда как у тебя сложность O(n^2) - так называемый квадратный код, присущий новичкам.
первый проход - счетчик, второй - массив по условию
marvellikДа, что-то я протупил, видимо. Если так, то словарь не нужен тогда, достаточно одного множества для неуникальных элементов и потом список по второму разу пройти и выбрать элементы, входящие во множество неуникальных. Это оптимальный алгоритм.
py.user.next так результат не соответствует заданию
Отредактировано py.user.next (Апрель 4, 2018 12:27:53)
Офлайн
73
py.user.next можно и с словарем но результаты говорят сами за себя
from time import time def f_1(dat): dict_data = {} for i,x in enumerate(data): dict_data[x] = dict_data.get(x,0)+1 print(list(filter(lambda x : dict_data.get(x) > 1,data ))) def f_2(data): print(list(filter(lambda x : data.count(x) > 1 ,data)))
[1, 2, 1, 2, 'a', 'a'] 0.01300048828125 [1, 2, 1, 2, 'a', 'a'] 0.00500035285949707
Офлайн
marvellikименно
результаты говорят сами за себя
from time import time def f1(lst): return [i for i in lst if lst.count(i)-1] def f2(lst): d = {} for i in lst: d.setdefault(i,-1) d[i] += 1 return [i for i in lst if d[i]] def f_1(data): dict_data = {} for i,x in enumerate(data): dict_data[x] = dict_data.get(x,0)+1 return list(filter(lambda x : dict_data.get(x) > 1,data )) def f_2(data): return list(filter(lambda x : data.count(x) > 1 ,data)) l = list(range(10000)) + [3,2,1,4] t0 = time() l1 = f1(l) print('f1',time() - t0,l1) t0 = time() l2 = f2(l) print('f2',time() - t0,l2) t0 = time() l2 = f_1(l) print('f_1',time() - t0,l2) t0 = time() l2 = f_2(l) print('f_2',time() - t0,l2)
f1 1.8496160507202148 [1, 2, 3, 4, 3, 2, 1, 4]
f2 0.006292819976806641 [1, 2, 3, 4, 3, 2, 1, 4]
f_1 0.011389970779418945 [1, 2, 3, 4, 3, 2, 1, 4]
f_2 1.859050989151001 [1, 2, 3, 4, 3, 2, 1, 4]
Отредактировано vic57 (Апрель 4, 2018 12:40:59)
Офлайн
857
Короче, получился вариант, эквивалентный варианту vic57
>>> lst = [1, 2, 3, 1, 2, 4, 'a', 'b', 'a'] >>> >>> seen = {} >>> >>> for e in lst: ... seen[e] = seen.get(e, 0) + 1 ... >>> out = [i for i in lst if seen[i] > 1] >>> out [1, 2, 1, 2, 'a', 'a'] >>>
marvellikПобольше элементов возьми и enumerate() там не нужен.
py.user.next можно и с словарем но результаты говорят сами за себя
Офлайн
0
py.user.next Спасибо! Вот что у меня получилось: Список проходится один раз, нет итерационных count(), remove(). Теперь нужно вникнуть в запись покороче)))
data = [10, 6, 9, 10, 10, 9, 8, 4] dict = {} a = set() for i in range(len(data)): if data[i] not in dict: if data[i] not in a: dict[data[i]] = i else: a.add(data[i]) else: a.add(data[i]) dict.pop(data[i]) for value in sorted(dict.values(), reverse = True): data.pop(value) print(data)
Офлайн
73
vic57 да точно на больших списках с словарем работает быстрее
py.user.nextно все равно код vic57 из всех вариантов самый быстрый на 2-3 сотых быстрее
Короче, получился вариант, эквивалентный варианту vic57
Офлайн
marvellikя читал что dict.setdefault() быстрее чем dict.get()
но все равно код vic57 из всех вариантов самый быстрый на 2-3 сотых быстрее
from time import time from collections import Counter def f1(lst): d = {} for i in lst: d.setdefault(i,-1) d[i] += 1 return [i for i in lst if d[i]] def f2(lst): c = Counter(lst) return [i for i in lst if c[i] != 1] l = list(range(100000)) + [3,2,1] t0 = time() l1 = f1(l) print(time() - t0,l1) t0 = time() l1 = f2(l) print(time() - t0,l1)
0.042214155197143555 [1, 2, 3, 3, 2, 1] 0.03288602828979492 [1, 2, 3, 3, 2, 1]
Офлайн
857
marvellikРассматриваем только разницу в скорости в два раза. Если код быстрее хотя бы в два раза, то он быстрее, иначе это всё погрешности.
но все равно код vic57 из всех вариантов самый быстрый на 2-3 сотых быстрее
Офлайн