Форум сайта python.su
py.user.nextну а как надо через итераторы? я не вижу физического смысла вычислять ф-цию от пустой строки.
Ещё ты не только используешь исключения там, где надо без них обходиться, так ты ещё перехватываешь исключение StopIteration, которое вообще считается служебным. То есть перехват этого исключения - признак сам знаешь чего.
Офлайн
vic57Это я твою функцию поправил минимально
ну а как надо через итераторы?
>>> def f(s): ... it = iter(s) ... prev = next(it, None) ... count = 1 ... out = '' ... while prev: ... try: ... curr = next(it) ... if prev == curr: count += 1 ... else: ... out += prev + str(count) ... count = 1 ... prev = curr ... except StopIteration: ... out += prev + str(count) ... break ... return out ... >>> f('') '' >>> f('a') 'a1' >>> f('ab') 'a1b1' >>> f('aabb') 'a2b2' >>>
vic57Ты можешь не обрабатывать None, поданный в функцию, но пустая строка входит во множество всех строк. Когда эта функция будет использоваться в какой-нибудь программе, туда запросто может пустая строка попасть. И ещё, функция, обрабатывающая любые строки, ценнее функции, обрабатывающей лишь часть строк. Ценнее потому, что эта функция подходит для решения большего числа задач. То есть у неё более высокий коэффициент реюза. Мы её можем использовать не в 50 проектах, а в 100 проектах. Чем больше у тебя таких функций с высоким реюзом, тем быстрее ты будешь делать новые проекты. Это как салат из полуфабрикатов готовить: можно выращивать овощи, пропалывать, собирать их там, чистить и нарезать; а можно купить уже нарезанные овощи и просто смешать их с майонезом. За одно и то же время у тебя разный результат получается. То же самое с функциями: ты можешь в каждом проекте писать их заново, а можешь в одном проекте их написать, а потом в сотню других проектов их просто скопировать.
я не вижу физического смысла вычислять ф-цию от пустой строки.
Отредактировано py.user.next (Дек. 9, 2017 04:37:01)
Офлайн
ну не проще на входе сделать
if not s: return ''
Офлайн
vic57Нужно и так и так уметь делать. Потому что в этом случае это просто выглядит и нужно одну шпуньку проверить, а в других случаях надо проверить десять шпунек и все непростые. Просто заполнишь функцию так, что она нечитаемой станет.
ну не проще на входе сделать
Отредактировано py.user.next (Дек. 9, 2017 04:43:47)
Офлайн
def f(s): if not s: return '' it = iter(s) prev = next(it) count = 1 out = '' while True: try: curr = next(it) if prev == curr: count += 1 else: out += prev + str(count) count = 1 prev = curr except StopIteration: out += prev + str(count) break return out
Офлайн
py.user.nextделаю простое сравнение f() - итератор, f1() - индекс, func() - из твоего поста
Но по скорости, понятности, стильности она, конечно, должна быть полностью переделана.
def f(s): if not s: return '' it = iter(s) prev = next(it) count = 1 out = '' while True: try: curr = next(it) if prev == curr: count += 1 else: out += prev + str(count) count = 1 prev = curr except StopIteration: out += prev + str(count) break return out def f1(s): if not s: return '' out = '' prev = s[0] count = 1 ln = len(s) for i in range(1,ln): curr = s[i] if prev == curr: count += 1 else: out += prev + str(count) count = 1 prev = curr out += prev + str(count) return out def func(s): res = '' state = 0 ch = '' n = 0 i = 0 slen = len(s) while i < slen: c = s[i] if state == 0: # first char ch = c n = 1 if i + 1 == slen: res = ch + str(n) state = 1 elif state == 1: # other char if c == ch: # matched n += 1 if i + 1 == slen: res += ch + str(n) else: # didn't match res += ch + str(n) ch = c n = 0 i -= 1 i += 1 return res s = 'qqqwwweeerrrtttttyXYZ' from time import time t0 = time() for i in range(100000): t = f(s) t1 = time() print(t1-t0,t) t0 = time() for i in range(100000): t = f1(s) t1 = time() print(t1-t0,t) t0 = time() for i in range(100000): t = func(s) t1 = time() print(t1-t0,t)
0.9916658401489258 q3w3e3r3t5y1X1Y1Z1# итератор 0.8220779895782471 q3w3e3r3t5y1X1Y1Z1 # индекс 1.3592848777770996 q3w3e3r3t5y1X1Y1Z1 # ф-ция из поста py user next
Офлайн
Вот я тут написал новую версию
>>> def f(s): ... if s == '': ... return s ... out = '' ... prev = '' ... n = 0 ... for ch in s: ... if ch == prev or prev == '': ... pass ... else: ... out += prev + str(n) ... n = 0 ... prev = ch ... n += 1 ... out += prev + str(n) ... return out ... >>> f('') '' >>> f('a') 'a1' >>> f('aa') 'a2' >>> f('ab') 'a1b1' >>> f('aaaarufnnbjff') 'a4r1u1f1n2b1j1f2' >>>
import itertools def f(s): return ''.join(c + str(len(tuple(g))) for c, g in itertools.groupby(s))
#!/usr/bin/env python3
import timeit
def func1(s):
if not s: return ''
it = iter(s)
prev = next(it)
count = 1
out = ''
while True:
try:
curr = next(it)
if prev == curr: count += 1
else:
out += prev + str(count)
count = 1
prev = curr
except StopIteration:
out += prev + str(count)
break
return out
def func2(s):
if not s: return ''
out = ''
prev = s[0]
count = 1
ln = len(s)
for i in range(1,ln):
curr = s[i]
if prev == curr: count += 1
else:
out += prev + str(count)
count = 1
prev = curr
out += prev + str(count)
return out
def func3(s):
res = ''
state = 0
ch = ''
n = 0
i = 0
slen = len(s)
while i < slen:
c = s[i]
if state == 0: # first char
ch = c
n = 1
if i + 1 == slen:
res = ch + str(n)
state = 1
elif state == 1: # other char
if c == ch: # matched
n += 1
if i + 1 == slen:
res += ch + str(n)
else: # didn't match
res += ch + str(n)
ch = c
n = 0
i -= 1
i += 1
return res
def func4(s):
if s == '':
return s
out = ''
prev = ''
n = 0
for ch in s:
if ch == prev or prev == '':
pass
else:
out += prev + str(n)
n = 0
prev = ch
n += 1
out += prev + str(n)
return out
import itertools
def func5(s):
return ''.join(c + str(len(tuple(g))) for c, g in itertools.groupby(s))
def f1():
func1('aaabbbcde' * 100)
def f2():
func2('aaabbbcde' * 100)
def f3():
func3('aaabbbcde' * 100)
def f4():
func4('aaabbbcde' * 100)
def f5():
func5('aaabbbcde' * 100)
def main():
t1 = timeit.Timer('f1()', 'from __main__ import f1')
t2 = timeit.Timer('f2()', 'from __main__ import f2')
t3 = timeit.Timer('f3()', 'from __main__ import f3')
t4 = timeit.Timer('f4()', 'from __main__ import f4')
t5 = timeit.Timer('f5()', 'from __main__ import f5')
for t in t1, t2, t3, t4, t5:
print(t.repeat(3, 10000))
if __name__ == '__main__':
main()
[guest@localhost rlecomp]$ ./rlecompcmp.py
[3.3369056259980425, 3.323838824995619, 3.326331812000717] # твоя итератор
[2.8052678310050396, 2.7940210589949857, 2.83161843400012] # твоя индексы
[5.913237972999923, 5.912506636996113, 5.872607308003353] # моя старая
[2.6772045339967008, 2.676720352996199, 2.6726658850020613] # моя новая
[4.964137271002983, 4.971889730004477, 4.978617688000668] # моя новая короткая
[guest@localhost rlecomp]$
Прикреплённый файлы: rlecomp.tar (10,0 KБ)
Офлайн
крайний вариант оказался самым быстрым. я по аналогии с Си считал что наиболее быстрый метод - указатель(итератор).
Офлайн