Suppose I want to create an iterator class that takes another iterator as an input and counts the frequency of the elements. I cannot use lists, dicts, or any other data structure that could be used to store information for multiple elements together so I have to solve this by creating some sort of a nested iteration. Conceptually, I want my class to do the following:
for i in iter(input):
count=0
for j in iter(input):
if i=j:
count+=1
if j = None: #iterator is done
# reset j
# move to next element of i
This is obviously a simplified example in many ways but I hope the general intended structure of my class is clear. Each time I save the value of i and the count to disk but we can ignore that for now.
The first problem I come across is that Python does not allow iterators to be reset once they are consumed which creates an issue with resetting the inner loop (j). I overcome this using itertools.cycle() when initiating the second iterator which allows endless iteration. Unfortunately, my code below only does one succesfull pass over the data and the first if statement does not return the next value of the outer iterator but instead treats it as if it has been already consumed.
class Match:
def __init__(self, input):
'''
Input is an iterator
'''
self.in1 = input
self.in2 = input
self.c=0 #the count
def __iter__(self):
'''
Initializes the iterators and fetches the first element
'''
self.it1 = iter(self.in1) # initialize the first (outer) iterator
self.it2 = itertools.cycle(iter(self.in2)) # initialize the second (inner) iterator
self.i = next(self.it1) #pin the first elements
self.j = next(self.it2)
return self
def _inc_outter_end(self):
'''increment or end outer iterator'''
try:
self.i = next(self.it1)
except StopIteration:
self.i = None
self.j = None
def __next__(self):
i = self.i
j = self.j
self.j = next(self.it2)
self.c+=1
if self.c ==9:
self.c=0
self._inc_outter_end()
i = self.i
#stop if done
elif i == None:
raise StopIteration()
#skip non-pairs
elif i != j:
return self.__next__()
#count and return matches
elif i==j:
return self.c
Running something like:
i1 = [1,7,2,4,6,6,1,1,3]
for match in Match(iter(i1)):
print(match)
does one pass over the data such that i is always 1 but instead of doing 8 more passes (for all the next elements of the input) stops. Instead I would like it to return the same output as:
i1 = [1,7,2,4,6,6,1,1,3]
for i in i1:
count=0
for j in i1:
if i==j:
count+=1
print(i,count)
giving
1 3
7 1
2 1
4 1
6 2
6 2
1 3
1 3
3 1