Index-Error: string index out of range - - python

def find_starman(board):
row_number = 0
column_number = 0
for star in board:
for j in range(len(board):
for i in range(len(board):
if star[j][i] == '*':
j += 1
i += 1
return [j,i]
I have no idea, everytime I ran the program, it says it is out of range?
How can I fix this?
(Also, forgot to say the question, when if finds the "*" it returns j+1 and i+1 )

For for loops, you don't need to increment the iterator in the loop body as it will automatically update to the new value after each loop (in this case, an increment of 1 since you're assigning it to iterate over range with steps of 1).
In other words, these lines are unnecessary:
j += 1
i += 1
Furthermore, from your edited question, it seems you'd like to return the coordinates (i+1, j+1) of the found *'s. In that case:
1) If you want to return those coordinates for only the first * you can find, and immediately exit the function, you can do:
if star[j][i] == '*':
return (j+1, i+1)
2) If you want to return the coordinates for all the *'s in your array, you can create new variables (like an empty list) before you build your loop, and for every run of the for loop, store the i+1 and j+1 of the found * as a child tuple/list to that variable (using append). In other words, something like this:
found_coordinates = []
for i in range(len(board)):
for j in range(len(board)):
if star[i][j] == '*':
found_coordinates.append((j+1, i+1))
In any case, your iterators (i and j) are either immediately returned or stored in another object, and should not be modified (using += or something else) inside a for loop.

You should remove j+=1 and i+=1 from your code and modify your return like this: return(j+1, i+1). I think thats what you want to do.
if star[j][i] == '*':
return [j+1,i+1]

Related

Recursion and List Mutation

I am restrict myself to mutate a list using recursion only, I have a few small troubles when doing so.
def expand_strings(L,s,i):
if len(L) == 0:
return
else:
if len(L[0]) - 1 <= i:
L[0] += s
elif len(L[0]) - 1 > i:
new_string = L[0][:i] + s + L[0][i:]
L[0] = new_string
expand_strings(L[1:], s, i)
return
L: The input list containing possible 1 or more strings
s: The extra portion of string that I need to "insert" or "append" to the string elements within the list
i: The index of string where I want to insert or append s to.
The main goal of this function is the following:
1. if the index i within the range 0 ~ len(string_element_in_list), then I insert my s starting from index i
2. if the index i is larger than what the current string length, then I do the append s.
The problems I am having right now is that: I notice the recursion will only mutate the first element within the input list, and every element after the first element, they won't be affected by the mutation, I figure it might have something to do with the new input list I pass to the recursion, but I don't know precisely why this doesn't work.
Thanks for helping in advance. :)
The problem is in the recursive call expand_strings(L[1:], s, i). When you use slicing to get a part of your list, python creates a whole new copy of that sublist. So the recursive call creates a copy of your list, except the first element, and works on that copy.
One way of solving this problem can be returning the modified list from your method:
def expand_strings(L,s,i):
if len(L) == 0:
return []
else:
if len(L[0]) - 1 <= i:
L[0] += s
elif len(L[0]) - 1 > i:
new_string = L[0][:i] + s + L[0][i:]
L[0] = new_string
return [L[0]] + expand_strings(L[1:], s, i)
If you don't want to create a copy of the sublist every time (and return the modified list), you can add one more parameter to your method that would specify the location of the first element to modify. The base case would be where the starting index is equal to the length of the list.
def expand_strings(L,s,i,start):
if start == len(L):
return
if len(L[start]) - 1 <= i:
L[start] += s
else:
L[start] = L[start][:i] + s + L[start][i:]
expand_strings(L, s, i, start + 1)

iterating over a changeable iterator in every iteration

I am trying to implement the code below, and I'm getting an error of
"index is out of range". I think I am getting the error because the for loop saved the value of the length of the array, while I changed it inside the loop itself.
I can't figure out how to solve it using a for loop.
I did solve it using a recursive way, but it was computationally expensive and I am dealing with billions of words. BTW, the Comp function only returns a pool if the 2 words having the same sentence, so I believe it doesn't effect.
I am using Python-3, pycharm.
def reg(array,n):
f=open(r"C:\Users\Ali\Desktop\love.txt","w")
length= len(array)
if length==1:
return array
k=0
for item in range (length-1):
k+=1
for j in range(k,length):
if Comp(array[item][0],array[j][0])>=n:
f.write(str("\n"))
f.write(str(array[item][1]))
f.write(str("\n"))
f.write(str(array[j+k ][1]))
array[k+j]=array.pop()
length-=1
break
f.close()
pass
Instead of modifying the array, just keep track of your effective last index and break out when you hit it. Something like (untested)
k = 0
last_index = len(array) - 1
for item in range(length - 1):
if item > last_index:
break
k += 1
# ....
array[k+j] = array[last_index]
last_index -= 1
break

How do I check every element in an appended text in python

I am doing the Euler project questions and the question I am on right now is least common multiple. Now I can go the simple route and get the factors and then find the number that way, but I want to make my life hard.
This is the code I have so far in Python:
i = 0
j = 0
count = []
for i in range (1,10):
for j in range(1,11):
k = i%j
count.append(k)
print(count)
Now when I print this out I get an array and every time I goes through the loop, the previous information is appended on with it. How can I make it so that the previous information is not appended?
Second once I get that information how can I look at each value in the array and only print out those elements that are equal to 0? I feel like I have to use the all() function but for some reason I just dont get how to use it.
Any and all help is appreciated.
For your first question, you should know the scope of variable. Just define the variable count inside the outer loop and before the inner loop starts.
You can try this if you want nothing but zero elements.
print [element for element in count if element == 0]
If I understand your question right the answer for your question is like this.
i = 0
j = 0
for i in range (1,10):
# Resetting so that count will not have previous values
count = []
for j in range(1,11):
k = i%j
count.append(k)
# printing all the indexes where the value is '0'
print([index for index, item in enumerate(count) if item == 0])
You know your range of extern loop so you can just write your code in this way :
count = []
for i in range (1,10):
for j in range(1,11):
k = i%j
if(i == 9):
count.append(k)
print(count)
print("Without 0:")
print([x for x in count if x is not 0])

Python-Merge sort difficulties

I attempted to implement a merge sort, here is my code:
def mergeSort(array):
result=[]
n=len(array)
if n==1:
result=array
else:
a=round(n/2)
first=mergeSort(array[0:a])
second=mergeSort(array[a:n])
for i in range(len(first)):
for j in range(len(second)):
if first[i]<second[j]:
result.append(first[i])
i=i+1
else:
result.append(second[j])
j=j+1
return result
a=[5,4,1,8,7,6,2,3]
b=mergeSort(a)
print(b)
Unfortunately, the result turns out to be [1]. What is wrong with my function?
A number of things...
Firstly, this is a recursive function, meaning you cannot create a list within the function, as you did here:
result=[]
This will simply reset your list after every recursive call, skewing your results. The easiest thing to do is to alter the list that is passed as a parameter to merge sort.
Your next problem is that you have a for loop within a for loop. This will not work because while the first for loop iterates over first, the second for loop will iterate over second for every increment of i, which is not what you want. What you need is to compare both first and second and extract the minimum value, and then the next minimum value, and so on until you get a sorted list.
So your for loops need to be changed to the following:
while i < len(first) and j < len(second):
Which leads me to final problem in your code. The while loop will exit after one of the conditions are met, meaning either i or j (one or the other) will not have reached len(first) or len(second). In other words, there will be one value in either first or second that is unaccounted for. You need to add this unaccounted value to your sorted list, meaning you must implement this final excerpt at the end of your function:
remaining = first if i < j else second
r = i if remaining == first else j
while r < len(remaining):
array[k] = remaining[r]
r = r + 1
k = k + 1
Here r represents the index value where the previous while loop broke off. The while loop will then iterate through the rest of the remaining values; adding them to the end of your sorted list.
You merge sort should now look as follows:
def mergeSort(array):
if len(array)==1:
return array
else:
a=round(len(array)/2)
first=mergeSort(array[:a])
second=mergeSort(array[a:])
i = 0
j = 0
k = 0
while i < len(first) and j < len(second):
if first[i]<second[j]:
array[k] = first[i]
i=i+1
k=k+1
else:
array[k] = second[j]
j=j+1
k=k+1
remaining = first if i < j else second
r = i if remaining == first else j
while r < len(remaining):
array[k] = remaining[r]
r += 1; k += 1
return array
I tried to not alter your code as much as possible in order to make it easier for you to understand. However, if your difficulty in understanding what I did persists, try de-bugging your merge sort using multiple print statements so that you can follow the function's progress and see where it goes wrong.

returning indices using a while loop

I'm trying to take an input of a list of numbers and return the list of indices in the original list that contain negative values. I also want to use a while loop. Here is my code so far.
def scrollList2(myList):
negativeIndices = []
i = 0
while i < len(myList):
if myList[i] < 0:
i = i + 1
negativeIndices.append(i)
return negativeIndices
How to I stop the loop and how do i get the indices to return? Right now when I run it, it runs forever (infinite loop) how do I tell it to stop once it hits the last indices of myList?
When you hit your first non-negative number, the if is never entered again and i never gets incremented again. Put the part where you increment i outside the if block.
while i < len(myList):
if myList[i] < 0:
i = i + 1
negativeIndices.append(i)
Assume, the conditional myList[i] < 0 is not true. In that case, i won’t be incremented and nothing else happens either. So you will end up in the next iteration, with the same value of i and the same conditional. Forever, in an endless loop.
You will want to increment i regardless of whether you matched something or not. So you will have to put the increment outside of the if conditional. Furthermore, you want to increment i after appending the index to the list, so you actually append the index you tested, and not the one afterwards:
while i < len(myList):
if myList[i] < 0:
negativeIndices.append(i)
i = i + 1
Also, you would usually use a for loop here. It will automatically take care of giving you all the values of i which you need to index every element in myList. It works like this:
negativeIndices = []
for i in range(len(myList)):
if myList[i] < 0:
negativeIndices.append(i)
range(len(myList)) will give you a sequence of values for every number from zero to the length of the list (not including the length itself). So if your list holds 4 values, you will get the values 0, 1, 2 and 3 for i. So you won’t need to take care of incrementing it on your own.
Another possibility would be enumerate as Foo Bar User mentioned. That function will take a sequence, or list in your case, and will give you both an index and the value at the same time:
negativeIndices = []
for i, value in enumerate(myList):
if value < 0:
negativeIndices.append(i)
As you can see, this completely removes the need to even access the list by its index.
OP wants to use a while loop, so this answer is not exactly on point - but I feel I should point out that many pythonistas will expect something like:
neg_indices = [k for k,v in enumerate(myList) if v < 0]
This is implicit in the other answers, however it might be useful for lurkers and for OP to consider down the road... While certainly does the job as the other answers show, but its 'free' in a list comprehension; plus, there's no chance of an infinite loop here....

Categories