Форум сайта python.su
253
Мне кажется вы со своими мудрствованиями запутаете коллег.
py.user.nextДля большинства последовательностей это очевидно не так.
А randint() требует вычисления длины - операция по времени такая же, как и поиск
import time L=1000000 li=list(range(L)) ######## t0=time.clock() a=len(li) t1=time.clock() print("len") print(t1-t0) ######## t0=time.clock() a=li[L/2] t1=time.clock() print("index") print(t1-t0) ######## t0=time.clock() a=li.index(L/2) t1=time.clock() print("linear search") print (t1-t0) ######## t0=time.clock() for i,v in enumerate(li): pass t1=time.clock() print("enumerate") print (t1-t0)import time
len 3.2163095698e-06 index 2.03719608012e-06 linear search 0.0106376918778 enumerate 0.104751248308
py.user.next
А у некоторых последовательностей вообще длина не вычисляется
from itertools import cycle tuple(enumerate(cycle("123")))
Отредактировано doza_and (Июль 18, 2015 13:55:36)
Офлайн
857
doza_andЯ ему говорю, как оно будет дальше развиваться. А дальше он будет делать функцию, которая всё это инкапсулирует. А когда делаешь функцию, нужно оставлять как можно меньше ограничений у формальных параметров.
Мне кажется вы со своими мудрствованиями запутаете коллег.
doza_andАлгоритмически равно O(n) как вычисление длины, так и поиск элемента. Получается двухпроходный алгоритм O(2n). А если ещё и операцию сравнения при поиске учитывать - то O(3n).
Для большинства последовательностей это очевидно не так.
doza_andТам это время ушло на цикл for, который неявно вызывает ещё функции.len
3.2163095698e-06
index
2.03719608012e-06
linear search
0.0106376918778
enumerate
0.104751248308
#!/usr/bin/env python3 import timeit def f1(): import random WORDS = ("питон", "мышь", "кислород", "карандаш", "ответ", "стакан") index, word = random.choice(tuple(enumerate(WORDS))) def f2(): import random WORDS = ("питон", "мышь", "кислород", "карандаш", "ответ", "стакан") iword = random.randint(0, len(WORDS) - 1) word = WORDS[iword] iword, word def main(): t1 = timeit.Timer('f1()', 'from __main__ import f1') t2 = timeit.Timer('f2()', 'from __main__ import f2') for t in t1, t2: print(t.repeat(3, 10000)) if __name__ == '__main__': main()
[guest@localhost py]$ ./timecmp.py
[0.07288823899943964, 0.06414823500017519, 0.06307941100021708]
[0.05327650500021264, 0.051950771000520035, 0.05130656600067596]
[guest@localhost py]$
doza_andНу, типа функции ему писать не надо, пусть это остаётся на уровне кода новичка.
Да, запросто можно представить такую последовательность (которые конечно не имеют отношения к тому что спрашивал ТС
doza_andФункция должна быть общей, то есть быть применимой в как можно большем числе случаев. Это ослабление предусловия.
поскольку у него явно указан tuple
>>> import random >>> >>> def f1(): ... WORDS = {"питон", "мышь", "кислород", "карандаш", "ответ", "стакан"} ... index, word = random.choice(tuple(enumerate(WORDS))) ... return index, word ... >>> def f2(): ... WORDS = {"питон", "мышь", "кислород", "карандаш", "ответ", "стакан"} ... iword = random.randint(0, len(WORDS) - 1) ... word = WORDS[iword] ... return iword, word ... >>> f1() (3, 'кислород') >>> f2() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in f2 TypeError: 'set' object does not support indexing >>>
doza_andНе, он вообще длину не ищёт, это просто зипование чисел с элементами последовательности.
enumerate работает потому что длину считает перебором элементов
doza_andА в таком случае оба не будут подходить, потому что невозможно вернуть последний элемент (если он случайный) бесконечной последовательности и его индекс. Индекс равен бесконечности.
Например интересно как ваш алгоритм будет работать с такой последовательностью:
Офлайн
253
py.user.nextДа это сложный архитектурный выбор. Приходится или ограничивать общность или жертвовать быстродействием. Редко когда удается совместить оба варианта.
Функция должна быть общей, то есть быть применимой в как можно большем числе случаев.
#!/usr/bin/env python # -*- coding: utf-8 -*- import timeit def f1(): import random WORDS = ("питон", "мышь", "кислород", "карандаш", "ответ", "стакан")*1000 index, word = random.choice(tuple(enumerate(WORDS))) def f2(): import random WORDS = ("питон", "мышь", "кислород", "карандаш", "ответ", "стакан")*1000 iword = random.randint(0, len(WORDS) - 1) word = WORDS[iword] iword, word def main(): t1 = timeit.Timer('f1()', 'from __main__ import f1') t2 = timeit.Timer('f2()', 'from __main__ import f2') for t in t1, t2: print(t.repeat(3, 10000)) if __name__ == '__main__': main()
[6.969264377437743, 7.330539255925593, 6.922474260426043] [0.38192501650165056, 0.38119296129612934, 0.3821524152415243]
py.user.nextКстати замечу что в моем посте разница не 10 а 10000 раз. Поскольку последовательность размером в миллион элементов.
Так что то якобы десятикратное преимущество над enumerate - это просто for.
import random class Tx: def __init__(self,m): self.m=m def __getitem__(self,i): return str(i*self.m) obj = Tx(3) def get_randelm(obj): try: L=obj.len() except: L = 0xffffffff # :( Хак return obj[random.randint(0, L)] obj = Tx(3) >>> get_randelm(obj) '11432516094'
Отредактировано doza_and (Июль 19, 2015 09:47:37)
Офлайн
857
doza_andОсновное замедление происходит из-за tuple. Это повторное создание входного списка.
и, наверное, tuple имеют трудоемкость О где N Длина последовательности
Отредактировано py.user.next (Июль 20, 2015 05:58:58)
Офлайн
0
import random
WORDS = (“питон”, “мышь”, “кислород”, “карандаш”, “ответ”, “стакан”)
print(“Индекс случайно выбранного элемента:”,WORDS.index(random.choice(WORDS)))
Вот так просто будет
Отредактировано Manu_Vilks.Py (Авг. 30, 2015 15:17:43)
Офлайн