Уведомления

Группа в Telegram: @pythonsu

#1 Авг. 27, 2010 18:11:22

Isem
От:
Зарегистрирован: 2010-08-27
Сообщения: 447
Репутация: +  7  -
Профиль   Отправить e-mail  

Клонирование итератора

Ed
def minmax3(iterable):
isorted = sorted(iterable)
return isorted, isorted
Этот вариант так быстро сработал потому, что сам по себе список уже отсортированный. Если ему подсунуть случайный список, то время увеличивается раз в 10



Офлайн

#2 Авг. 27, 2010 18:16:52

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

Клонирование итератора

Насчет не менее читабельного вы явно погорячились.
Я про первый вариант вообще молчу, но даже во втором вот это:

functools.reduce( cmp, it, 2*(it[0],) ) if it else None
читабельным можно назвать с большой натяжкой. Впрочем, наверное это субъективно.



Офлайн

#3 Авг. 27, 2010 18:18:35

Isem
От:
Зарегистрирован: 2010-08-27
Сообщения: 447
Репутация: +  7  -
Профиль   Отправить e-mail  

Клонирование итератора

Ed
1. Напишите лямбда функцию
2. Напишите комментарий, объясняющий что за хренотень она делает.
3. Поизучайте комментарий какое-то время и подумайте об имени, которое бы показывало сущность коментария
4. Преобразуйте вашу лямбду в обычную функцию, используя это имя
5. Удалите комментарий
:)

Для случайного списка результат таков:

result for minmax of shuffled list: (0, 1999999), ‘time spent:0.825999975204
result for minmax1 of shuffled list: (0, 1999999), ’time spent:0.703999996185
result for minmax2 of shuffled list: (0, 1999999), ‘time spent:0.604000091553
result for minmax3 of shuffled list: (0, 1999999), ’time spent:3.10199999809



Офлайн

#4 Авг. 27, 2010 18:30:05

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

Клонирование итератора

У меня получается так:
result for minmax: (0, 1999999), ‘time spent:7.46938109398
result for minmax1: (0, 1999999), ’time spent:0.92161488533
result for minmax2: (0, 1999999), ‘time spent:0.899652004242
result for minmax3: (0, 1999999), ’time spent:3.92543697357
result for minmax4: (0, 1999999), 'time spent:1.45591902733

Для такого кода:

import functools
import random
from time import time

def minmax1(iterable):
minm = None
maxm = None
for item in iterable:
if maxm is None or item > maxm:
maxm = item
if minm is None or item < minm:
minm = item
return minm, maxm

def minmax( it, key = lambda self: self ):
return functools.reduce( lambda pair, x: (x,x) if pair is None else ( +min(x, pair[0], key=key), max(x, pair[1], key=key) ), it, None )

def minmax2(iterable):
return min(iterable), max(iterable)

def minmax3(iterable):
isorted = sorted(iterable)
return isorted[0], isorted[-1]

def minmax4(it):
def cmp( pair, x ):
if x < pair[0]: return x, pair[1]
if x > pair[1]: return pair[0], x
return pair
return functools.reduce( cmp, it, 2*(it[0],) ) if it else None

data = range(2000000)
random.shuffle(data)
for fun in minmax, minmax1, minmax2, minmax3, minmax4:
start = time()
print("result for {0}: {1}, 'time spent:{2}".format( fun.__name__, fun(data), time() - start ))



Офлайн

#5 Авг. 27, 2010 18:45:20

Isem
От:
Зарегистрирован: 2010-08-27
Сообщения: 447
Репутация: +  7  -
Профиль   Отправить e-mail  

Клонирование итератора

Можно сделать вывод, что функции min и max реализованы на си и особенно эффективны для больших списков. Однако их частый вызов в циклах для коротких списков приводит к заметному снижению производительности.



Офлайн

#6 Авг. 27, 2010 18:49:30

Isem
От:
Зарегистрирован: 2010-08-27
Сообщения: 447
Репутация: +  7  -
Профиль   Отправить e-mail  

Клонирование итератора

Если вашу функцию переписать вот так:
def minmax1(iterable):
if not iterable: return (None, None)
minm = iterable
maxm = minm
for item in iterable:
if item > maxm:
maxm = item
if item < minm:
minm = item
return minm, maxm

то она начинает работать быстрее двухпроходной:

result for minmax of shuffled list: (0, 1999999), ‘time spent:0.819000005722
result for minmax1 of shuffled list: (0, 1999999), ’time spent:0.514000177383
result for minmax2 of shuffled list: (0, 1999999), 'time spent:0.598000049591



Офлайн

#7 Авг. 27, 2010 18:56:04

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

Клонирование итератора

У меня такое извращение показало наименьшее время:

def minmax5(iterable):
itera = iter(iterable)
minm = maxm = itera.next()
for item in itera:
if item > maxm:
maxm = item
elif item < minm:
minm = item
return minm, maxm
result for minmax1: (0, 1999999), ‘time spent:0.870595932007
result for minmax2: (0, 1999999), ’time spent:0.919430017471
result for minmax3: (0, 1999999), ‘time spent:3.98846888542
result for minmax4: (0, 1999999), ’time spent:1.37609004974
result for minmax5: (0, 1999999), 'time spent:0.659359931946



Офлайн

#8 Авг. 27, 2010 19:01:56

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

Клонирование итератора

Так нехорошо: minm = iterable
Сразу исчезает возможность работать с итераторами.



Офлайн

#9 Авг. 27, 2010 19:20:37

Isem
От:
Зарегистрирован: 2010-08-27
Сообщения: 447
Репутация: +  7  -
Профиль   Отправить e-mail  

Клонирование итератора

А в третьем питоне это работает прекрасно.
Например ragne(100) дает 3, хотя range() возвращает именно итератор
Конечно, это обращение по времени как o(n), но для первого элемента (точнее нулевого) - нормально



Офлайн

#10 Авг. 27, 2010 19:40:20

Isem
От:
Зарегистрирован: 2010-08-27
Сообщения: 447
Репутация: +  7  -
Профиль   Отправить e-mail  

Клонирование итератора

Есть такая интересная задачка. Допустим, есть итератор, довольно сложный, который генерирует, например, длинные строки (1000 символов каждая, скажем).
Нужно определить длину цикла этого итератора. Но надо учитывать, что цикл может начинаться (и заканчиваться, соответственно) не с первого элемента, а совсем с другого. Сама же последовательность итератора может быть очень длинная.
Вот упрощенный (цифровой) пример списка, который генерирует итератор: ( 61,7,3,5,48, 54,34,62,221,31,67, 54,34,62,221,31,67, 54……. и т.д.)
Видно, что цикл начинается с числа 54 и длина цикла равна 6.
Возможно, это оффтопик для данной ветки, однако же все равно она бы умерла, если бы мы ее не оживили.:)



Отредактировано (Авг. 27, 2010 19:57:03)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version