Im trying to create a sequence of jobs, and put them in an array. the coding works if I run the lines separately. The one problem is that it does not stop the while loop when 'count' equals 'amountofmachines' it gives the error:
IndexError: list assignment index out of range
Im a bit new to python and used to Matlab. How can I end this while loop and make the code resume at the line a.sort() ?
import random
import numpy as np
from random import randint
MachineNumber = 6 #amount of machines imported from Anylogic
JobNumber = 4 #amount of job sequences
JobSeqList = np.zeros((JobNumber,MachineNumber), dtype=np.int64)
amountofmachines = randint(1, MachineNumber) #dictated how much machines the order goes through
a = [0]*amountofmachines #initialize array of machines sequence
count = 0 #initialize array list of machines
element = [n for n in range(1, MachineNumber 1)]
while count <= amountofmachines:
a[count] = random.choice(element)
element.remove(a[count])
count = count 1
a.sort() #sorts the randomized sequence
A = np.asarray(a) #make an array of the list
A = np.pad(A, (0,MachineNumber-len(a)), 'constant') #adds zeros to the end of sequence
#add the sequence to the array of all sequences
JobSeqList[0,:] = A[:]
CodePudding user response:
I have tested your code, and found the answer!
Matlab indexes start at 1, so the first item in a list would be at 1..
However, python indexes start at 0, so the first item in a list would be at 0…
Change this line:
while count <= amountofmachines
To be:
while count < amountofmachines
Updated Code:
import random
import numpy as np
from random import randint
MachineNumber = 6 #amount of machines imported from Anylogic
JobNumber = 4 #amount of job sequences
JobSeqList = np.zeros((JobNumber,MachineNumber), dtype=np.int64)
amountofmachines = randint(1, MachineNumber) #dictated how much machines the order goes through
a = [0]*amountofmachines #initialize array of machines sequence
count = 0 #initialize array list of machines
element = [n for n in range(1, MachineNumber 1)]
while count < amountofmachines:
a[count] = random.choice(element)
element.remove(a[count])
count = count 1
a.sort() #sorts the randomized sequence
A = np.asarray(a) #make an array of the list
A = np.pad(A, (0,MachineNumber-len(a)), 'constant') #adds zeros to the end of sequence
#add the sequence to the array of all sequences
JobSeqList[0,:] = A[:]
CodePudding user response:
The problem with your while
loop using <
vs <=
has already been answered, but I'd like to go a bit further and suggest that building a list in this way (by having a counter you increment or decrement manually) is something that's almost never done in Python in the first place, in the hope that giving you some more "pythonic" tools will help you avoid similar stumbling blocks in the future as you're getting used to Python. Python has really great tools for iterating over and building data structures that eliminate a lot of opportunities for minor errors like this, by taking all the "busy work" off of your shoulders.
All of this code:
a = [0]*amountofmachines #initialize array of machines sequence
count = 0 #initialize array list of machines
element = [n for n in range(1, MachineNumber 1)]
while count < amountofmachines:
a[count] = random.choice(element)
element.remove(a[count])
count = count 1
a.sort() #sorts the randomized sequence
amounts to "build a sorted array of amountofmachines
unique numbers taken from range(1, MachineNumber 1)
", which can be more simply expressed using random.sample
and sorted
:
a = sorted(random.sample(range(1, MachineNumber 1), amountofmachines))
Note that a = sorted(a)
is the same as a.sort()
-- sorted
does a sort and returns the result as a list, whereas sort
does an in-place sort on an existing list. In the line of code above, random.sample
returns a list of random elements taken from the range, and sorted
returns a sorted version of that list, which is then assigned to a
.
If random.sample
didn't exist, you could use random.shuffle
and a list slice. This of this as shuffling a deck of cards (element
) and then taking amountofmachines
cards off the top before re-sorting them:
element = [n for n in range(1, MachineNumber 1)]
random.shuffle(element)
a = sorted(element[:amountofmachines])
If neither of those existed and you had to use random.choice
to pick elements one by one, there are still easier ways to built a list through iteration; there's no need to statically pre-allocate the list, and there's no need to track your iteration with a counter you manage yourself, because for
does that for you:
a = []
element = [n for n in range(1, MachineNumber 1)]
for i in range(amountofmachines):
a.append(random.choice(element))
element.remove(a[i])
a.sort()
To make it simpler yet, it's not necessary to even have the for
loop keep track of i
for you, because you can access the last item in a list with [-1]
:
a = []
element = [n for n in range(1, MachineNumber 1)]
for _ in range(amountofmachines):
a.append(random.choice(element))
element.remove(a[-1])
a.sort()
and to make it simpler yet, you can use pop()
instead of remove()
:
a = []
element = [n for n in range(1, MachineNumber 1)]
for _ in range(amountofmachines):
a.append(element.pop(random.choice(range(len(element)))))
a.sort()
which could also be expressed as a list comprehension:
element = [n for n in range(1, MachineNumber 1)]
a = [
element.pop(random.choice(range(len(element))))
for _ in range(amountofmachines)
]
a.sort()
or as a generator expression passed as an argument to sorted
:
element = [n for n in range(1, MachineNumber 1)]
a = sorted(
element.pop(random.choice(range(len(element))))
for _ in range(amountofmachines)
)