views:

171

answers:

3

This code is supposed to be able to sort the items in self.array based upon the order of the characters in self.order. The method sort runs properly until the third iteration, unil for some reason the for loop seems to repeat indefinitely. What is going on here?

Edit: I'm making my own sort function because it is a bonus part of a python assignment I have.

class sorting_class:
    def __init__(self):
        self.array = ['ca', 'bd', 'ac', 'ab'] #An array of strings
        self.arrayt = []
        self.globali = 0
        self.globalii = 0
        self.order = ['a', 'b', 'c', 'd'] #Order of characters
        self.orderi = 0
        self.carry = []
        self.leave = []
        self.sortedlist = []
    def sort(self):
        for arrayi in self.arrayt:  #This should only loop for the number items in self.arrayt. However, the third time this is run it seems to loop indefinitely. 
            print ('run', arrayi)   #Shows the problem
            if self.order[self.orderi] == arrayi[self.globali]:
                self.carry.append(arrayi)
            else:
                if self.globali != 0:
                    self.leave.append(arrayi)
    def srt(self):
        self.arrayt = self.array
        my.sort() #First this runs the first time.
        while len(self.sortedlist) != len(self.array):
            if len(self.carry) == 1:
                self.sortedlist.append(self.carry)
                self.arrayt = self.leave
                self.leave = []
                self.carry = []
                self.globali = 1
                self.orderi = 0
                my.sort()
            elif len(self.carry) == 0:
                if len(self.leave) != 0: #Because nothing matches 'aa' during the second iteration, this code runs the third time"
                    self.arrayt = self.leave
                    self.globali = 1
                    self.orderi += 1
                    my.sort()
                else:
                    self.arrayt = self.array
                    self.globalii += 1
                    self.orderi = self.globalii
                    self.globali = 0
                    my.sort()
                    self.orderi = 0
            else: #This is what runs the second time.
                self.arrayt = self.carry
                self.carry = []
                self.globali += 1
                my.sort()
my = sorting_class()  
my.srt()
+2  A: 

During the third pass of your loop you are appending new elements to the list you are iterating over therefore you can never leave the loop:
self.arrayt = self.leave - this assignment leads to the fact that self.leave.append(arrayi) will append elements to the list self.arrayt refers to.

In general you may think about creating copies of lists not just assigning different variables/members to the same list instances.

Li0liQ
+2  A: 

You have self.arrayt = self.leave which makes arrayt refer to exactly the same array as leave (it's not a copy of the contents!!!), then in the loop for arrayi in self.arrayt: you perpetrate a self.leave.append(arrayi) -- which lenghtens self.leave, which is just another name for the very list self.arrayt you're looping on. Appending to the list you're looping on is a good recipe for infinite loops.

This is just one symptom of this code's inextricable messiness. I recommend you do your sorting with the built-in sort method and put your energy into defining the right key= key-extractor function to get things sorted the exact way you want -- a much more productive use of your time.

Alex Martelli
Thanks I didn't realize that in this case = would point one variable at another. I'm making my own sort function for bonus marks on a python assignment.
Protean
@Protean, in a sensible course reinventing the wheel (using your own sort instead of Python's incredibly good one) should _cost_ points!-)
Alex Martelli
+2  A: 

The key-extractor Alex mentions is trivial enough to put in a lambda function

>>> array = ['ca', 'bd', 'ac', 'ab']
>>> order = ['a', 'b', 'c', 'd']
>>> sorted(array, key=lambda v:map(order.index,v))
['ab', 'ac', 'bd', 'ca']

>>> order = ['b', 'a', 'c', 'd']
>>> sorted(array, key=lambda v:map(order.index,v))
['bd', 'ab', 'ac', 'ca']

>>> order = ['d', 'c', 'b', 'a']
>>> sorted(array, key=lambda v:map(order.index,v))
['ca', 'bd', 'ac', 'ab']

Let's see how this works:

map calls the method order.index for each item in v and uses those return values to create a list.
v will be one of the elements of array

>>> order = ['a', 'b', 'c', 'd']
>>> map(order.index,array[0])
[2, 0]
>>> map(order.index,array[1])
[1, 3]
>>> map(order.index,array[2])
[0, 2]
>>> map(order.index,array[3])
[0, 1]

The function is supplied as a key= to sort, so internally those lists are being sorted instead of the strings.

gnibbler