Форум сайта python.su
А, убрать строки у которых есть повторяющиеся друг за другом символы?
Вот мой вариант:
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)
Офлайн
Вариант с izip в примере Ed должен быть самым оптимальным:
# ...
for a, b in itertools.izip(str[:-1], str[1:]):
if a == b:
return False
# ...
Офлайн
Не уверен. По-моему будет медленнее за счет вызова itertools.izip и того, что делается внутри него. Я уже не говорю об импорте.
Офлайн
Решил проверить, дабы не быть голословным. Медленнее в 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)
Офлайн
Ага, а 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)
Отредактировано (Авг. 19, 2010 15:44:06)
Офлайн
Не быстрее, а еще медленнее :). Вы взяли урезаный пример.
Вот, смотрите:
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)
Офлайн
А с islice еще медленнее:
1.54072403908
3.86018490791
Офлайн
А вот как быстрее, нет лишних вызовов:
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)
Офлайн
> Вы взяли урезаный пример.
Нифига не правда :-). Я взял другую задачу (т.е. ситуацию), где itertools эффективнее. Ещё раз смотрим на мой пример и обращаем внимание на размер моего массива “l” (10000 элементов) и вашего “str” (1 элемент, полагаю что это просто опечатка, увеличьте до >1000 и посмотрите что произойдёт, и используйте islice).
..bw
Отредактировано (Авг. 19, 2010 18:12:08)
Офлайн
Правда-правда :) Насчет размера массива я не понял, поясните, плз.
Но вообще используя урезаный код трудно надеяться на взаимопонимание. У меня используется полный пример - фильтрация списка. Я не сам его придумал - это топикстартер сделал.
Вы же взяли из него 2 строки и что-то пытаетесь доказать. Это неправильный подход. просто исправьте мой код, добавьте туда ваш случай. Тогда это будет наглядно.
PS: Собственно я это и пытался сделать. Посмотрите внимательнее.
Отредактировано (Авг. 19, 2010 17:57:43)
Офлайн