Radix sorting, "Queue" object not iterable - python

I've come to an end with my assignment, I don't know where I go from where I am right now, the code is currently looking like this:
def radixsorting1(n,m):
div=1
mod=10
bin_list=[]
alist=[]
r=[]
s=[]
for bins in range(0,10):
bin_list.append(Queue())
for k in range(0,m):
r.append(random.randint(1,10**n))
if not len(r)==0:
o=max(r)
y=len(str(o))
for p in range(y):
for num in r:
minsta_tal=num%mod
minsta_tal=int(minsta_tal//div)
bin_list[minsta_tal].put(num)
new_list=[]
for bins in bin_list:
while not bins.isempty():
new_list.append(bins.dequeue())
alist=new_list
return alist
What I've been trying to do is to create 10 queues in put them in a list, then random m numbers from 1 to 10^n. Lets say I get 66 and 72, then I first sort them by the "small number", that is 6 and 2 in my numbers, then put them in a lost, and then do the process all over again but for the number 6 and 7 (the bigger number). In its current shape I get the error "Queue" object is not iterable.
My Queue class is looking like this, I think this one is okay.
class Queue:
def __init__(self):
self.lista=[]
def put(self,x):
self.lista.append(x)
def get(self):
if not len(self.lista)==0:
return self.lista.pop(0)
def isempty(self):
if len(self.lista)==0:
return True
else:
False
def length(self):
return len(self.lista)
def dequeue(self):
if not len(self.lista)==0:
n=self.lista.pop(0)
return n

You need to add a bit more code to make it an iterable. __iter__ should return an iterator. The iterator should have a next method.
Take a look at this:
Build a Basic Python Iterator
So it is my understanding that the thing you want to iterate over is the contents of self.lista... Why not just return lista's iterator.
Here is the easiest way to do that:
class Queue:
...
def __iter__(self):
return self.lista.__iter__()
It's a bit hard to see what exactly it is that you want.. If what you are trying to do is empty listaas you iterate over it (Queue is a fifo kinda deal) it then rather do this:
class Queue:
...
def __iter__(self):
return self
def next(self):
if self.lista: #since empty lists are Falsey
return self.lista.pop(0)
raise StopIteration

Related

Get length of a (non infinite) iterator inside it's loop using Python 2.7

I'm working with some iterator generated using itertools.imap, and I was thinking if there is a way to access the iterator length inside the for-loop that I use to loop over the elements.
What I can say for sure is that the iterator doesn't generate an infinite amount of data.
Also, because the information I'm looping are from a query to a database, I can get the length of the information from there, but the function I'm using has to return an iterator.
I thought of some options:
def iterator_function(some, arguments, that, I, need):
query_result = query()
return_iterator = itertools.imap(
mapping_function,
query_result
)
return return_iterator
Because I cannot change the returned iterator, I thought of something (really ugly) like:
query_result = query()
query_size = len(query_result)
return_iterator = itertools.imap(
lambda item: (mapping_function(item), query_size),
query_result
)
return return_iterator
But I don't really like this option, and I was thinking if there is a way, in Python, to get the iterator size from inside the loop over the iterator, something like:
for item in iterator():
print item.iterator_length()
# do other stuff
Or even something like:
for item in iterator():
print iterator.length() # or iterator().length()???
Thanks!
I don't know if my idea is correct but how about class generator pattern
and trying to add sequence bahaviour :
if your class represents something that has a length, don't define a GetLength method; define the __len__ method and use len(instance).
something like this :
class firstn(object):
def __init__(self, n):
self.n = n
self.num, self.nums = 0, []
def __iter__(self):
return self
# Python 3 compatibility
def __next__(self):
return self.next()
# V------- Something like this
def __len__(self):
return self.my_length
def next(self):
if self.num < self.n:
cur, self.num = self.num, self.num+1
return cur
else:
raise StopIteration()
Also, because the information I'm looping are from a query to a
database, I can get the length of the information from there, but the
function I'm using has to return an iterator.
Assuming you have a good database, do the count there. Doubt any solution in python will be faster/cleaner.

How can I have multiple iterators over a single python iterable at the same time?

I would like to compare all elements in my iterable object combinatorically with each other. The following reproducible example just mimics the functionality of a plain list, but demonstrates my problem. In this example with a list of ["A","B","C","D"], I would like to get the following 16 lines of output, every combination of each item with each other. A list of 100 items should generate 100*100=10,000 lines.
A A True
A B False
A C False
... 10 more lines ...
D B False
D C False
D D True
The following code seemed like it should do the job.
class C():
def __init__(self):
self.stuff = ["A","B","C","D"]
def __iter__(self):
self.idx = 0
return self
def __next__(self):
self.idx += 1
if self.idx > len(self.stuff):
raise StopIteration
else:
return self.stuff[self.idx - 1]
thing = C()
for x in thing:
for y in thing:
print(x, y, x==y)
But after finishing the y-loop, the x-loop seems done, too, even though it's only used the first item in the iterable.
A A True
A B False
A C False
A D False
After much searching, I eventually tried the following code, hoping that itertools.tee would allow me two independent iterators over the same data:
import itertools
thing = C()
thing_one, thing_two = itertools.tee(thing)
for x in thing_one:
for y in thing_two:
print(x, y, x==y)
But I got the same output as before.
The real-world object this represents is a model of a directory and file structure with varying numbers of files and subdirectories, at varying depths into the tree. It has nested links to thousands of members and iterates correctly over them once, just like this example. But it also does expensive processing within its many internal objects on-the-fly as needed for comparisons, which would end up doubling the workload if I had to make a complete copy of it prior to iterating. I would really like to use multiple iterators, pointing into a single object with all the data, if possible.
Edit on answers: The critical flaw in the question code, pointed out in all answers, is the single internal self.idx variable being unable to handle multiple callers independently. The accepted answer is the best for my real class (oversimplified in this reproducible example), another answer presents a simple, elegant solution for simpler data structures like the list presented here.
It's actually impossible to make a container class that is it's own iterator. The container shouldn't know about the state of the iterator and the iterator doesn't need to know the contents of the container, it just needs to know which object is the corresponding container and "where" it is. If you mix iterator and container different iterators will share state with each other (in your case the self.idx) which will not give the correct results (they read and modify the same variable).
That's the reason why all built-in types have a seperate iterator class (and even some have an reverse-iterator class):
>>> l = [1, 2, 3]
>>> iter(l)
<list_iterator at 0x15e360c86d8>
>>> reversed(l)
<list_reverseiterator at 0x15e360a5940>
>>> t = (1, 2, 3)
>>> iter(t)
<tuple_iterator at 0x15e363fb320>
>>> s = '123'
>>> iter(s)
<str_iterator at 0x15e363fb438>
So, basically you could just return iter(self.stuff) in __iter__ and drop the __next__ altogether because list_iterator knows how to iterate over the list:
class C:
def __init__(self):
self.stuff = ["A","B","C","D"]
def __iter__(self):
return iter(self.stuff)
thing = C()
for x in thing:
for y in thing:
print(x, y, x==y)
prints 16 lines, like expected.
If your goal is to make your own iterator class, you need two classes (or 3 if you want to implement the reversed-iterator yourself).
class C:
def __init__(self):
self.stuff = ["A","B","C","D"]
def __iter__(self):
return C_iterator(self)
def __reversed__(self):
return C_reversed_iterator(self)
class C_iterator:
def __init__(self, parent):
self.idx = 0
self.parent = parent
def __iter__(self):
return self
def __next__(self):
self.idx += 1
if self.idx > len(self.parent.stuff):
raise StopIteration
else:
return self.parent.stuff[self.idx - 1]
thing = C()
for x in thing:
for y in thing:
print(x, y, x==y)
works as well.
For completeness, here's one possible implementation of the reversed-iterator:
class C_reversed_iterator:
def __init__(self, parent):
self.parent = parent
self.idx = len(parent.stuff) + 1
def __iter__(self):
return self
def __next__(self):
self.idx -= 1
if self.idx <= 0:
raise StopIteration
else:
return self.parent.stuff[self.idx - 1]
thing = C()
for x in reversed(thing):
for y in reversed(thing):
print(x, y, x==y)
Instead of defining your own iterators you could use generators. One way was already shown in the other answer:
class C:
def __init__(self):
self.stuff = ["A","B","C","D"]
def __iter__(self):
yield from self.stuff
def __reversed__(self):
yield from self.stuff[::-1]
or explicitly delegate to a generator function (that's actually equivalent to the above but maybe more clear that it's a new object that is produced):
def C_iterator(obj):
for item in obj.stuff:
yield item
def C_reverse_iterator(obj):
for item in obj.stuff[::-1]:
yield item
class C:
def __init__(self):
self.stuff = ["A","B","C","D"]
def __iter__(self):
return C_iterator(self)
def __reversed__(self):
return C_reverse_iterator(self)
Note: You don't have to implement the __reversed__ iterator. That was just meant as additional "feature" of the answer.
Your __iter__ is completely broken. Instead of actually making a fresh iterator on every call, it just resets some state on self and returns self. That means you can't actually have more than one iterator at a time over your object, and any call to __iter__ while another loop over the object is active will interfere with the existing loop.
You need to actually make a new object. The simplest way to do that is to use yield syntax to write a generator function. The generator function will automatically return a new iterator object every time:
class C(object):
def __init__(self):
self.stuff = ['A', 'B', 'C', 'D']
def __iter__(self):
for thing in self.stuff:
yield thing

I am trying make a function that takes a number as a parameter and removes all occurrences of it from a Queue

class Queue:
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def add(self, item):
self.items.append(item)
def remove(self):
self.items.reverse()
return self.items.pop()
I need to create a function that takes in a number as a parameter and a queue then removes every occurrence of that number in the queue but with the exception of the omissions. I've put up a model of what my Queue looks like above and I'll put a model of what the queue should somewhat look like (It's very messy and in its early stages) below.
def remove_item(q, val):
q_temp = Queue
while not q.is_empty():
q_temp.add(q.remove)
remove_item()
I cannot directly modify it in any way and I can't put the elements of the Queue in a normal list. Anyone got any solutions?
Edit: Also it needs to be executable in IDLE like this
remove_item(queue,number)
What I would do is something like this:
number_to_remove = 123
for i in range(0, queue.length()):
number = queue.remove()
if number != number_to_remove:
queue.add(number)
That way you "loop" trough the queue, you look at every number and if it's not the number you should remove then just add it again. You need to create the .length() method though.
That code will fail because bad indentation:
def remove_item(q, val):
#> q_temp = Queue
And you're setting q_temp to the class, not to an instance, making that it can't be modified.
q_temp = Queue()
And, the .remove method doesn't work, there's an easier way to make it work:
def remove(self):
return self.items.pop(-1)
But I don't have a (fully valid) answer. I we could get the queue's items, I'd use conditional list comprehensions for deleting determinated items, and applying that into the queue.
def removeFromQueue(queue, value = ""):
items = queue.items
queue.items = [i for i in items if i != value]
return queue
You can do if you let us to use the Queue class use only the class methods (we can make variables, make another queues, .remove and .add numbers, but not to use .items) you can do this:
def removeFromQueue(queue, value = ""):
items = []
for i in len(queue):
items.append(queue.remove())
items = [i for i in items if i != value]:
for i in items:
queue.add(items.pop(0))
I don't think that's valid, though. And it would need defining Queue.__len__()*:
def __len__(self):
return len(self.items)
* or modififying the code and defining __iter__ or some sort of thing like that

python design custom iterator

I am designing a custom iterator in python:
class Iterator():
def __init__(self):
return
def fit(self, n):
self.n = n
return self
def __iter__(self):
for i in range(self.n):
yield i
return
it = Iterator().fit(10)
for i in it:
print(i)
it.fit(20)
for i in it:
print(i)
It is working fine but I am wondering if it is possible that a new fit is called before that the previous one is finished leading to strange behaviour of the class.
If yes how should I design it to make it more robust?
It is important to have some parameters passed from the fit method.
EDIT: I will introduce an example that is similar to my original problem
The iterator class is designed to be used by a User class. It is important that when the evaluate method is called all the numbers until n/k are printed. Without any exception.
Maybe the use of a iterator.fit(n) method solves the problem?
class Iterator():
def __init__(self, k):
self.k = k
return
def fit(self, n):
for i in range(int(n/self.k)):
yield i
return
class User():
def __init__(self, iterator):
self.iterator = iterator
return
def evaluate(self, n):
for i in self.iterator.fit(n):
print(i)
return
it = Iterator(2)
u = User(it)
u.evaluate(10) # I want to be sure that all the numbers until 9 are printed
u.evaluate(20) # I want to be sure that all the numbers until 20 are printed
Because each call to range creates a new iterator, there will be no conflicts if you make multiple calls to fit.
Your class is a bit weird. You could either remove the __init__, as it does nothing, or put the fit method in there.
it = Iterator()
it1 = iter(it.fit(10))
it2= iter(it.fit(5))
print it1.next()
print it1.next()
print it2.next()
print it1.next()
>>0
1
0
2
You haven't actually written an iterator -- you've written a normal class that can return an iterator. The iterator that you are returning is a generator.
What this means is that calling fit() during iteration will have no effect -- at least, not until you iterate over your object again. For example:
>>> it = Iterator()
>>> for x in it.fit(7):
... it.fit(3)
... print(x)
...
0
1
2
3
4
5
6
>>> for x in it:
... print(x)
...
0
1
2

__getitem__ invocation in for loop

I am learning Python I don't get one thing. Consider this code:
class Stack:
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def __getitem__(self,index):
print "index",index
return self.items[index]
def __len__(self):
return len(self.items)
stack = Stack()
stack.push(2)
stack.push(1)
stack.push(0)
for item in stack:
print item
and the output
index 0
2
index 1
1
index 2
0
index 3
Why is getitem called four times?
The for loop doesn't know how to iterate over your object specifically because you have not implemented __iter__(), so it uses the default iterator. This starts at index 0 and goes until it gets an IndexError by asking for index 3. See http://effbot.org/zone/python-for-statement.htm.
Your implementation would be a lot simpler if you derived from list, by the way. You wouldn't need __init__(), pop(), or __getitem__(), and push could be just another name for append. Also, since list has a perfectly good __iter()__ method, for will know how to iterate it without going past the end of the list.
class Stack(list):
push = list.append

Categories

Resources