I'm currently using something like
>> import itertools
>> ABC = [a, b, c]
>> abc = itertools.cycle( ABC )
>> next( abc )
a
>> next( abc )
b
>> next( abc )
c
I want my next call to be
>> previous( abc )
b
Is there a method in itertools that can accomplish this?
No, there isn't.
Because of the way Python's iteration protocol works, it would be impossible to implement previous without keeping the entire history of the generated values. Python doesn't do this, and given the memory requirements you probably wouldn't want it to.
You can use deque from collections module and rotate method,
for example:
from collections import deque
alist=['a','b','c']
d=deque(alist)
current = d[0]
print(current) # 'a'
d.rotate(1) # rotate one step to the right
current = d[0]
print(current) # 'c'
d.rotate(-1) # rotate one step to the left
current = d[0]
print(current) # 'a' again
You can write your own class to emulate an iterable object with next and previous. This is the simplest implementation:
class cycle:
def __init__(self, c):
self._c = c
self._index = -1
def __next__(self):
self._index += 1
if self._index>=len(self._c):
self._index = 0
return self._c[self._index]
def previous(self):
self._index -= 1
if self._index < 0:
self._index = len(self._c)-1
return self._c[self._index]
ABC = ['a', 'b', 'c']
abc = cycle(ABC)
print(next(abc))
print(next(abc))
print(next(abc))
print(abc.previous())
Although deque is the way to go, here's another example:
Code
import itertools as it
class Cycle:
"""Wrap cycle."""
def __init__(self, seq):
self._container = it.cycle(seq)
self._here = None
self.prev = None
def __iter__(self):
return self._container
def __next__(self):
self.prev = self._here
self._here = next(self._container)
return self._here
Demo
c = Cycle("abc")
next(c)
# 'a'
next(c)
# 'b'
c.prev
# 'a'
Related
Is there a Python class or module that implements a structure that is similar to the BitSet?
There's nothing in the standard library. Try:
http://pypi.python.org/pypi/bitarray
Have a look at this implementation in Python 3.
The implementation basically makes use of the built-in int type, which is arbitrary precision integer type in Python 3 (where long is the Python 2 equivalent).
#! /usr/bin/env python3
"""
bitset.py
Written by Geremy Condra
Licensed under GPLv3
Released 3 May 2009
This module provides a simple bitset implementation
for Python.
"""
from collections import Sequence
import math
class Bitset(Sequence):
"""A very simple bitset implementation for Python.
Note that, like with normal numbers, the leftmost
index is the MSB, and like normal sequences, that
is 0.
Usage:
>>> b = Bitset(5)
>>> b
Bitset(101)
>>> b[:]
[True, False, True]
>>> b[0] = False
>>> b
Bitset(001)
>>> b << 1
Bitset(010)
>>> b >> 1
Bitset(000)
>>> b & 1
Bitset(001)
>>> b | 2
Bitset(011)
>>> b ^ 6
Bitset(111)
>>> ~b
Bitset(110)
"""
value = 0
length = 0
#classmethod
def from_sequence(cls, seq):
"""Iterates over the sequence to produce a new Bitset.
As in integers, the 0 position represents the LSB.
"""
n = 0
for index, value in enumerate(reversed(seq)):
n += 2**index * bool(int(value))
b = Bitset(n)
return b
def __init__(self, value=0, length=0):
"""Creates a Bitset with the given integer value."""
self.value = value
try: self.length = length or math.floor(math.log(value, 2)) + 1
except Exception: self.length = 0
def __and__(self, other):
b = Bitset(self.value & int(other))
b.length = max((self.length, b.length))
return b
def __or__(self, other):
b = Bitset(self.value | int(other))
b.length = max((self.length, b.length))
return b
def __invert__(self):
b = Bitset(~self.value)
b.length = max((self.length, b.length))
return b
def __xor__(self, value):
b = Bitset(self.value ^ int(value))
b.length = max((self.length, b.length))
return b
def __lshift__(self, value):
b = Bitset(self.value << int(value))
b.length = max((self.length, b.length))
return b
def __rshift__(self, value):
b = Bitset(self.value >> int(value))
b.length = max((self.length, b.length))
return b
def __eq__(self, other):
try:
return self.value == other.value
except Exception:
return self.value == other
def __int__(self):
return self.value
def __str__(self):
s = ""
for i in self[:]:
s += "1" if i else "0"
return s
def __repr__(self):
return "Bitset(%s)" % str(self)
def __getitem__(self, s):
"""Gets the specified position.
Like normal integers, 0 represents the MSB.
"""
try:
start, stop, step = s.indices(len(self))
results = []
for position in range(start, stop, step):
pos = len(self) - position - 1
results.append(bool(self.value & (1 << pos)))
return results
except:
pos = len(self) - s - 1
return bool(self.value & (1 << pos))
def __setitem__(self, s, value):
"""Sets the specified position/s to value.
Like normal integers, 0 represents the MSB.
"""
try:
start, stop, step = s.indices(len(self))
for position in range(start, stop, step):
pos = len(self) - position - 1
if value: self.value |= (1 << pos)
else: self.value &= ~(1 << pos)
maximum_position = max((start + 1, stop, len(self)))
self.length = maximum_position
except:
pos = len(self) - s - 1
if value: self.value |= (1 << pos)
else: self.value &= ~(1 << pos)
if len(self) < pos: self.length = pos
return self
def __iter__(self):
"""Iterates over the values in the bitset."""
for i in self[:]:
yield i
def __len__(self):
"""Returns the length of the bitset."""
return self.length
I wouldn't recommend that in production code but for competitive programming, interview preparation and fun, one should make themselves familiar with bit fiddling.
b = 0 # The empty bitset :)
b |= 1 << i # Set
b & 1 << i # Test
b &= ~(1 << i) # Reset
b ^= 1 << i # Flip i
b = ~b # Flip all
You might like to take a look at a module I wrote called bitstring (full documentation here), although for simple cases that need to be as fast as possible I'd still recommend bitarray.
Some similar questions:
What is the best way to do Bit Field manipulation in Python?
Does Python have a bitfield type?
Python Bitstream implementations
If the number of bits is finite, enum.IntFlag can be used as a bit set.
See https://docs.python.org/3/howto/enum.html#intflag
I have the following example in which the next method of a class is supposed to return the values from two generators:
class Test():
def __next__(self):
g1, g2 = self._gen1(), self._gen2()
return next(g1), next(g2)
def _gen1(self):
i = 0
while True:
yield i
i += 2
def _gen2(self):
i = 1
while True:
yield i
i += 2
However, when I call next for this class, the values are not incremented.
>>> t = Test()
>>> next(t)
>>> (0, 1)
>>> next(t)
>>> (0, 1)
What is wrong? Is there a more eloquent way to write this class?
Although I have no idea what you are trying to accomplish, here is a cleaned up version which (I think) does what you want.
class Test():
def __init__(self):
self.g1 = self._gen2()
self.g2 = self._gen1()
def __next__(self):
return next(self.g1), next(self.g2)
def _gen1(self):
i = 0
while True:
yield i
i += 2
def _gen2(self):
i = 1
while True:
yield i
i += 2
t = Test()
print(next(t))
print(next(t))
print(next(t))
Your code doesn't work because it recreates the generator functions every time __next__() is called, which effectively resets them back to their initial state before their next next() values are returned:
def __next__(self):
g1, g2 = self._gen1(), self._gen2() # Don't do this here.
return next(g1), next(g2)
You can fix that by adding an __init__() method and initializing them in it:
class Test:
def __init__(self):
self.g1, self.g2 = self._gen1(), self._gen2() # Initialize here.
def __next__(self):
return next(self.g1), next(self.g2)
...
A more eloquent and slightly more concise way to do it which likewise will avoid the problem would be to use the builtin zip() function to create an "iterator of generators" that will return pairs of next values from each generator every time it's called. Another advantage is it's very easy to extend to handle even more generators simply just changing the __init__() method.
Here's what I mean:
class Test:
def __init__(self):
self.generators = zip(self._gen1(), self._gen2())
def __next__(self):
return next(self.generators)
def _gen1(self):
i = 0
while True:
yield i
i += 2
def _gen2(self):
i = 1
while True:
yield i
i += 2
t = Test()
for _ in range(3):
print(next(t))
Output:
(0, 1)
(2, 3)
(4, 5)
I simply have enumerator with 3 modes ledOn, ledBlink, ledOFF and I have a variable mode that keeps track of modes for particular object. So for example I have one LED starting in mode ledOn i would like to for example after 5 seconds move to the next element which would be ledBlink then to ledOFF and then cycle through to ledON is there an easy way to achieve something like this?
import time
from threading import Thread
from enum import Enum
class ledController(Thread):
ledModes = Enum('ledModes', 'ledON ledBlink ledOFF')
def __init__(self, GPIOID, state=False, blinkDuration=2, mode=ledModes.ledON):
self.GPIOID = GPIOID
self.state = state
self.blinkDuration = blinkDuration
self.mode = mode
self.blinked = False
Thread.__init__(self)
def run(self):
if(self.mode == self.ledModes.ledON):
self.ledON()
if(self.mode == self.ledModes.ledBlink):
self.ledBlink()
if(self.mode == self.ledModes.ledOFF):
self.ledOFF()
time.sleep(self.blinkDuration)
self.mode.next()
def ledSwitch(self):
self.state = not self.state
print(self.ledDetails())
def ledON(self):
self.state = True
print(self.ledDetails())
def ledOFF(self):
self.state = False
print(self.ledDetails())
def ledBlink(self, duration):
self.ledON()
print(self.ledDetails())
time.sleep(self.Blinkduration)
self.ledOFF()
print(self.ledDetails())
time.sleep(self.Blinkduration)
def ledDetails(self):
return "Thread: "+self.getName()+", LED: "+str(self.GPIOID)+", State: "+str(self.state)+", Mode: "+str(self.mode.name)+", Blink duration: "+str(self.blinkDuration)
redLED = ledController(17, blinkDuration = 3)
blueLED = ledController(18, mode = ledController.ledModes.ledOFF)
redLED.setName('1')
blueLED.setName('2')
redLED.start()
blueLED.start()
redLED.join()
blueLED.join()
I would just use itertools.cycle instead of your enum:
>>> from itertools import cycle
>>> ledModes = cycle(['ledON', 'ledBlink', 'LedOFF'])
>>> first = next(ledModes)
>>> second = next(ledModes)
>>> third = next(ledModes)
>>> fourth = next(ledModes)
>>>
>>> first
'ledON'
>>> second
'ledBlink'
>>> third
'LedOFF'
>>> fourth
'ledON'
>>>
FYI, you can either do next(ledModes) or ledModes.next(), both are doing the same.
EDIT: You could use something like this, as method of your class:
from itertools import cycle
def initialize_cycle(start_mode):
states = ['ledON', 'ledBlink', 'ledOFF']
if start_mode not in states:
raise ValueError('start_mode invalid')
iterable = cycle(states)
for _ in states[:states.index(start_mode)]:
iterable.next()
return iterable
test1 = initialize_cycle('ledON')
test2 = initialize_cycle('ledOFF')
test3 = initialize_cycle('ledBlink')
# validation
for test in test1, test2, test3:
for _ in range(5):
print test.next()
print '-' * 20
Output:
$ python cycle.py
ledON
ledBlink
ledOFF
ledON
ledBlink
--------------------
ledOFF
ledON
ledBlink
ledOFF
ledON
--------------------
ledBlink
ledOFF
ledON
ledBlink
ledOFF
--------------------
The easiest fix for your current code is to:
change your run method, and
add a next_mode method:
like so:
def run(self):
while True:
set_mode = getattr(self, self.mode)
set_mode()
time.sleep(self.blinkDuration)
self.next_mode()
def next_mode(self):
self.mode = {
self.ledModes.ledON: self.ledModes.ledBlink,
self.ledModes.ledBlink: self.ledModes.ledOFF,
self.ledModes.ledOff: self.ledModes.ledOn,
}[self.mode]
Probably an overkill:
import itertools
class EnumCycler(object):
def __init__(self, enum, start_at=None):
self.enum = enum
self.members = list(enum.__members__.values())
self.start_at = self.members[0] if start_at is None else start_at
self.cycles = 0
def __iter__(self):
cycle = itertools.cycle(self.members)
sanity_check = len(self.members)
for value in cycle:
if sanity_check:
if value != self.start_at:
sanity_check -= 1
continue
sanity_check = 0
self.cycles += 1
yield value
Then:
>>> mode = Enum('ledModes', 'ledON ledBlink ledOFF')
>>> led_mode_cycler = EnumCycler(mode, start_at=mode.ledOFF)
>>> for value in led_mode_cycler:
... print(led_mode_cycler.cycles, value)
... if led_mode_cycler.cycles >= 10: break # infinite loop if we never break off
1 ledModes.ledOFF
2 ledModes.ledON
3 ledModes.ledBlink
4 ledModes.ledOFF
5 ledModes.ledON
6 ledModes.ledBlink
7 ledModes.ledOFF
8 ledModes.ledON
9 ledModes.ledBlink
10 ledModes.ledOFF
I am trying to generate the following sequence:
011212201220200112 ... constructed as follows: first is 0,
then repeated the following action:
already written part is attributed to the right with replacement
0 to 1, 1 to 2, 2 to 0.
E.g.
0 -> 01 -> 0112 -> 01121220 -> ...
I am trying to find the 3 billion-th element of this sequence.
I realized that the sequence grows exponentially and hence derived that:
log(base2) (3 billion) ~ 32
So I just need to generate this sequence 32 times.
Here is what I tried in python:
import os
import sys
s=['0']
num_dict = {'0':'1' , '1':'2' , '2':'0'}
def mapper(b):
return num_dict[b]
def gen(s):
while True:
yield s
s.extend( map(mapper,s) )
a = gen(s)
for i in xrange(32):
a.next()
print a.next()[3000000000 - 1]
The problem is my RAM gets filled up before hitting the 3 billion mark.
Is there a better way to do this problem ?
EDIT: This program could crash your machine.Please try for xrange(25) for testing purposes
There are enough hints in the comments that you should be able to find the one-line solution. I think that it's more interesting to try to derive it with a more general tool, namely, implicit data structures. Here's a class for singleton lists.
class Singleton:
def __init__(self, x):
self.x = x
def __getitem__(self, i):
if not isinstance(i, int): raise TypeError(i)
elif not (0 <= i < len(self)): raise IndexError(i)
else: return self.x
def __len__(self): return 1
We can use this class like so.
>>> lst = Singleton(42)
>>> lst[0]
42
>>> len(lst)
1
Now we define a concatenation class and a mapper class, where the latter takes a function and implicitly applies it to each list element.
class Concatenation:
def __init__(self, lst1, lst2):
self.lst1 = lst1
self.lst2 = lst2
self.cachedlen = len(lst1) + len(lst2)
def __getitem__(self, i):
if not isinstance(i, int): raise TypeError(i)
elif not (0 <= i < len(self)): raise IndexError(i)
elif i < len(self.lst1): return self.lst1[i]
else: return self.lst2[i - len(self.lst1)]
def __len__(self): return self.cachedlen
class Mapper:
def __init__(self, f, lst):
self.f = f
self.lst = lst
def __getitem__(self, i): return self.f(self.lst[i])
def __len__(self): return len(self.lst)
Now let's rewrite your code to use these classes.
a = Singleton(0)
for i in range(32):
a = Concatenation(a, Mapper({0: 1, 1: 2, 2: 0}.get, a))
print(a[3000000000 - 1])
As an exercise: why do we need cachedlen?
I have below snippet which use the generator to give the new ID
...
def __init__(self, id_generator = None):
if id_generator is None: id_generator = 0
if isinstance(id_generator, int):
import itertools
self._generator = itertools.count(id_generator)
else:
self._generator = id_generator
...
id = self._generator.next() #0
id = self._generator.next() #1
id = self._generator.next() #2
id = self._generator.next() #3
my question is, suppose I have an existing id number such as int(99) need to be accepted
during the runtime and need the _generator to generate the ID starting from 99.
looks like:
0
1
2
3
4
<---- new id number 99 be given in somehow
99
100
101
how I can feed it back to the _generator?
Just use self._generator = itertools.count(99) or there's a better way?
More, sucn a confuse can be to be more generalized: how I can memo/assign a generator's
status/value if it is not for an int type?
Thanks!
No, generators just generate items, you cannot set or save their state once they have been created. So self._generator = itertools.count(99) is really the best way to go.
What you can do is duplicate a generator with itertools.tee, which memorizes the output sequence from the first iterable and passes it to the new generators.
You can also write a generator that draws from a source you can change:
class counter(object):
def __init__(self, current=0):
self.current = current
def __iter__(self):
def iter():
while True:
yield self.current
self.current += 1 #
return iter()
def set(self,x):
self.current = x
s = counter()
t = iter(s)
print t.next() # 0
s.set(20)
print t.next() # 21