Уведомления

Группа в Telegram: @pythonsu

#1 Авг. 19, 2010 14:27:12

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

фильтр строк?

А, убрать строки у которых есть повторяющиеся друг за другом символы?
Вот мой вариант:

def hasnocc(str):
for i in xrange(1, len(str)):
if str[i-1] == str[i]:
return False
return True

>> print filter(hasnocc, ["fffds", "bla-bla", "fffdj", "fffdk", "fffdl", "fffjj", "fffjk", "fffjl", "123"])
>> ['bla-bla', '123']



Отредактировано (Авг. 19, 2010 14:35:04)

Офлайн

#2 Авг. 19, 2010 14:34:39

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

фильтр строк?

Вариант с izip в примере Ed должен быть самым оптимальным:

# ...
for a, b in itertools.izip(str[:-1], str[1:]):
if a == b:
return False
# ...
..bw



Офлайн

#3 Авг. 19, 2010 14:36:50

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

фильтр строк?

Не уверен. По-моему будет медленнее за счет вызова itertools.izip и того, что делается внутри него. Я уже не говорю об импорте.



Офлайн

#4 Авг. 19, 2010 15:05:58

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

фильтр строк?

Решил проверить, дабы не быть голословным. Медленнее в 2 раза:

from timeit import Timer

init = 'lst = ["1", "fffds", "bla-bla", "fffdj", "fffdk", "fffdl", "fffjj", "fffjk", "fffjl", "123"]'

init1 = """
from itertools import imap, izip
""" + init

init2 = """
def ifd(str):
for i in xrange(1, len(str)):
if str[i-1] == str[i]:
return False
return True
""" + init

init3 = """
def ifd(str):
for a,b in itertools.izip(str[:-1], str[1:]):
if a == b:
return False
return True
""" + init
print Timer('list((x for x in lst if 1 not in imap(len, imap(set, izip(x[1:], x[:-1])))))', init1).timeit(number=10000)
print Timer('filter(ifd, lst)', init2).timeit(number=10000)
print Timer('filter(ifd, lst)', init3).timeit(number=10000)
Результат:
0.559158086777
0.172734022141
0.352480888367



Офлайн

#5 Авг. 19, 2010 15:26:18

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

фильтр строк?

Ага, а len вызывать не нужно, литерал по индексу (дважды) с одной арифметической операцией делать не нужно :-) ?
Так правильнее: itertools.izip(l, itertools.islice(l, 1, None))
Хотя всё равно медленнее. На таких небольших массивах задачу всё же лучше решать в лоб. Получается медленно (видимо) из-за создания генератора (хотя xrange тоже генератор :-) или, неужели так сложно каждый цикл создавать кортеж (a и b).

p.s.

А вот так я быстрее:

import random
import timeit

l = [random.randint(0, 255) for i in xrange(10000)]

print timeit.Timer('''for a, b in itertools.izip(l, itertools.islice(l, 1, None)):
if a == b:
break''', 'import itertools; l = %r'%l).timeit(number = 10000)

print timeit.Timer('''for i in xrange(1, len(l)):
if l[i - 1] == l[i]:
break''', 'l = %r'%l).timeit(number = 10000)
..bw



Отредактировано (Авг. 19, 2010 15:44:06)

Офлайн

#6 Авг. 19, 2010 15:50:58

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

фильтр строк?

Не быстрее, а еще медленнее :). Вы взяли урезаный пример.
Вот, смотрите:

from timeit import Timer
from random import randrange

lst = [str(randrange(0, 255)) for i in xrange(10000)]
init = 'lst = %s' % str(lst)

init1 = """
def ifd(str):
for i in xrange(1, len(str)):
if str[i-1] == str[i]:
return False
return True
""" + init

init2 = """
import itertools
def ifd(str):
for a,b in itertools.izip(str[:-1], str[1:]):
if a == b:
return False
return True
""" + init
print Timer('filter(ifd, lst)', init1).timeit(number=100)
print Timer('filter(ifd, lst)', init2).timeit(number=100)
Результат:
1.55739688873
3.58278203011



Офлайн

#7 Авг. 19, 2010 15:53:47

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

фильтр строк?

А с islice еще медленнее:
1.54072403908
3.86018490791



Офлайн

#8 Авг. 19, 2010 16:09:52

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

фильтр строк?

А вот как быстрее, нет лишних вызовов:

init3 = """
def foo(lst):
for item in lst:
for i in xrange(1, len(item)):
if item[i-1] == item[i]:
break
else:
yield(item)
""" + init
print Timer('filter(ifd, lst)', init1).timeit(number=100)
print Timer('list(foo(lst))', init3).timeit(number=100)
1.57755303383
1.38983392715



Офлайн

#9 Авг. 19, 2010 17:02:00

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

фильтр строк?

> Вы взяли урезаный пример.
Нифига не правда :-). Я взял другую задачу (т.е. ситуацию), где itertools эффективнее. Ещё раз смотрим на мой пример и обращаем внимание на размер моего массива “l” (10000 элементов) и вашего “str” (1 элемент, полагаю что это просто опечатка, увеличьте до >1000 и посмотрите что произойдёт, и используйте islice).

..bw



Отредактировано (Авг. 19, 2010 18:12:08)

Офлайн

#10 Авг. 19, 2010 17:54:52

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

фильтр строк?

Правда-правда :) Насчет размера массива я не понял, поясните, плз.
Но вообще используя урезаный код трудно надеяться на взаимопонимание. У меня используется полный пример - фильтрация списка. Я не сам его придумал - это топикстартер сделал.
Вы же взяли из него 2 строки и что-то пытаетесь доказать. Это неправильный подход. просто исправьте мой код, добавьте туда ваш случай. Тогда это будет наглядно.

PS: Собственно я это и пытался сделать. Посмотрите внимательнее.



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

Офлайн

Board footer

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

Powered by DjangoBB

Lo-Fi Version