# -*- coding: utf-8 -*-
from __future__ import print_function
from itertools import islice, cycle, chain, izip, repeat
def detect_cycle(iterable):
'''Detect a cycle in iterable object.
Iterable must return an independend iterator on iter(iterable)'''
tortoise = iter(iterable)
tortoise_val = next(tortoise)
hare = islice(iter(iterable),None,None,2) #two steps at a time
#it will start from the first value and only then will be advancing 2 values at a time
hare_val = next(hare)
for tortoise_val, hare_val in izip(tortoise,hare):
if tortoise_val==hare_val:
break
hare = tortoise #put hare in the place of tortoise
hare_val = tortoise_val
tortoise = iter(iterable) #start tortoise from the very beginning
tortoise_val = next(tortoise)
mu = 0
for tortoise_val, hare_val in chain(repeat((tortoise_val, hare_val),1),izip(tortoise,hare)):
#begin with the current val of hare.val and the value of tortoise which is in the first position
if tortoise_val==hare_val:
break
mu += 1
lamb = 0
hare = tortoise
for hare_val in hare:
lamb += 1
if hare_val == tortoise_val: #check AFTER the first step by hare
break
print('mu: {0}'.format(mu))
print('lamb: {0}'.format(lamb))
if __name__ == '__main__':
class iterable(object):
'''Emulate the object returning iterators having cycles'''
def __init__(self,beginning,cycling):
'''
beginning: the beginning part with no cycles (its length corresponds to mu)
cycling: the part which will be cycling (its length corresponds to lamb)
'''
self.beginning = beginning
self.cycling = cycling
def __iter__(self):
return chain(iter(self.beginning),cycle(iter(self.cycling)))
detect_cycle(iterable('1234','678'))
IyAtKi0gY29kaW5nOiB1dGYtOCAtKi0KCmZyb20gX19mdXR1cmVfXyBpbXBvcnQgcHJpbnRfZnVuY3Rpb24KZnJvbSBpdGVydG9vbHMgaW1wb3J0IGlzbGljZSwgY3ljbGUsIGNoYWluLCBpemlwLCByZXBlYXQKCgpkZWYgZGV0ZWN0X2N5Y2xlKGl0ZXJhYmxlKToKICAgICcnJ0RldGVjdCBhIGN5Y2xlIGluIGl0ZXJhYmxlIG9iamVjdC4KICAgIEl0ZXJhYmxlIG11c3QgcmV0dXJuIGFuIGluZGVwZW5kZW5kIGl0ZXJhdG9yIG9uIGl0ZXIoaXRlcmFibGUpJycnCgogICAgdG9ydG9pc2UgPSBpdGVyKGl0ZXJhYmxlKQogICAgdG9ydG9pc2VfdmFsID0gbmV4dCh0b3J0b2lzZSkKICAgIGhhcmUgPSBpc2xpY2UoaXRlcihpdGVyYWJsZSksTm9uZSxOb25lLDIpICAjdHdvIHN0ZXBzIGF0IGEgdGltZQogICAgI2l0IHdpbGwgc3RhcnQgZnJvbSB0aGUgZmlyc3QgdmFsdWUgYW5kIG9ubHkgdGhlbiB3aWxsIGJlIGFkdmFuY2luZyAyIHZhbHVlcyBhdCBhIHRpbWUKICAgIGhhcmVfdmFsID0gbmV4dChoYXJlKQoKICAgIGZvciB0b3J0b2lzZV92YWwsIGhhcmVfdmFsIGluIGl6aXAodG9ydG9pc2UsaGFyZSk6CiAgICAgICAgaWYgdG9ydG9pc2VfdmFsPT1oYXJlX3ZhbDoKICAgICAgICAgICAgYnJlYWsKICAgIAogICAgaGFyZSA9IHRvcnRvaXNlICNwdXQgaGFyZSBpbiB0aGUgcGxhY2Ugb2YgdG9ydG9pc2UKICAgIGhhcmVfdmFsID0gdG9ydG9pc2VfdmFsCiAgICB0b3J0b2lzZSA9IGl0ZXIoaXRlcmFibGUpICNzdGFydCB0b3J0b2lzZSBmcm9tIHRoZSB2ZXJ5IGJlZ2lubmluZwogICAgdG9ydG9pc2VfdmFsID0gbmV4dCh0b3J0b2lzZSkKICAgIG11ID0gMAogICAgZm9yIHRvcnRvaXNlX3ZhbCwgaGFyZV92YWwgaW4gY2hhaW4ocmVwZWF0KCh0b3J0b2lzZV92YWwsIGhhcmVfdmFsKSwxKSxpemlwKHRvcnRvaXNlLGhhcmUpKToKICAgICAgICAjYmVnaW4gd2l0aCB0aGUgY3VycmVudCB2YWwgb2YgaGFyZS52YWwgYW5kIHRoZSB2YWx1ZSBvZiB0b3J0b2lzZSB3aGljaCBpcyBpbiB0aGUgZmlyc3QgcG9zaXRpb24KICAgICAgICBpZiB0b3J0b2lzZV92YWw9PWhhcmVfdmFsOgogICAgICAgICAgICBicmVhawogICAgICAgIG11ICs9IDEKCiAgICBsYW1iID0gMAogICAgaGFyZSA9IHRvcnRvaXNlCiAgICBmb3IgaGFyZV92YWwgaW4gaGFyZToKICAgICAgICBsYW1iICs9IDEKICAgICAgICBpZiBoYXJlX3ZhbCA9PSB0b3J0b2lzZV92YWw6ICNjaGVjayBBRlRFUiB0aGUgZmlyc3Qgc3RlcCBieSBoYXJlCiAgICAgICAgICAgIGJyZWFrCgogICAgcHJpbnQoJ211OiB7MH0nLmZvcm1hdChtdSkpCiAgICBwcmludCgnbGFtYjogezB9Jy5mb3JtYXQobGFtYikpCiAgICAgCgppZiBfX25hbWVfXyA9PSAnX19tYWluX18nOgogICAgCiAgICBjbGFzcyBpdGVyYWJsZShvYmplY3QpOgogICAgICAgICcnJ0VtdWxhdGUgdGhlIG9iamVjdCByZXR1cm5pbmcgaXRlcmF0b3JzIGhhdmluZyBjeWNsZXMnJycKICAgICAgICBkZWYgX19pbml0X18oc2VsZixiZWdpbm5pbmcsY3ljbGluZyk6CiAgICAgICAgICAgICcnJwpiZWdpbm5pbmc6IHRoZSBiZWdpbm5pbmcgcGFydCB3aXRoIG5vIGN5Y2xlcyAoaXRzIGxlbmd0aCBjb3JyZXNwb25kcyB0byBtdSkKY3ljbGluZzogdGhlIHBhcnQgd2hpY2ggd2lsbCBiZSBjeWNsaW5nIChpdHMgbGVuZ3RoIGNvcnJlc3BvbmRzIHRvIGxhbWIpCicnJwogICAgICAgICAgICBzZWxmLmJlZ2lubmluZyA9IGJlZ2lubmluZwogICAgICAgICAgICBzZWxmLmN5Y2xpbmcgPSBjeWNsaW5nCgogICAgICAgIGRlZiBfX2l0ZXJfXyhzZWxmKToKICAgICAgICAgICAgcmV0dXJuIGNoYWluKGl0ZXIoc2VsZi5iZWdpbm5pbmcpLGN5Y2xlKGl0ZXIoc2VsZi5jeWNsaW5nKSkpCgogICAgZGV0ZWN0X2N5Y2xlKGl0ZXJhYmxlKCcxMjM0JywnNjc4Jykp