Python while looping over list but not finding value - python

I have a while loop that is looping over a list trying to find the number 1. I have the code below and it loops over "almost" all the list but it does not find the index for value 1
numbers = [24, 10, 92, 28, 71, 1, 80, 70]
counter = 0
number_to_find = 1
def my_loop():
global counter
while counter > 6: #Also not sure while 7 doesn't work, says out of range?
if numbers[counter] == number_to_find:
print "Number found at position", counter
else:
print "Counter not found in position" , counter
counter = counter + 1
my_loop()
print my_loop()

This is a very confusing bit of code.
You print the output, but the function does not return anything. (It also prints things, but it does not return anything.)
The function has a while loop and also recurs upon itself. (There are some cases where this is appropriate, but this is not one of them.)
counter is initially 0, but your first check is if counter > 6. 0 is not greater than six. (This is not technically wrong, but very confusing.)
The value 1 is at index 5. Why are you looking for 6?
Once you have reached the desired index, you do not terminate the loop.

You can achieve what you're looking for using the following piece of code:
numbers = [24, 10, 92, 28, 71, 1, 80, 1, 70]
number_to_find = 1
for i,j in enumerate(numbers):
if j == number_to_find:
print i, "=>", j
# Output
>>> 5 => 1
>>> 7 => 1
If your numbers doesn't contains repeated numbers, you can use the following piece of code, as sugested by kojiro:
numbers = [24, 10, 92, 28, 71, 1, 80, 70]
number_to_find = 1
print numbers.index(number_to_find)
# Output
>>> 5
But if your code contains repeated chars, it'll show only the first ocurrence:
numbers = [24, 10, 92, 28, 71, 1, 80, 1, 70]
number_to_find = 1
print numbers.index(number_to_find)
# Output
>>> 5

while counter > 6:
If counter is greater than 6, it must be 7 or greater. If you're looping while counter > 7, you're indexing out of the range of the size of the list (which is indexed from 0 to 7).
global counter
Don't do this. You shouldn't use globals. There are good reasons
def my_loop():
...
my_loop()
You don't need recursion for this. This is quite simple with just a for loop (in fact, you can do it without that).
I'll post a few ways to solve this problem:
enumerate
def find_needle(needle, haystack):
for idx, item in enumerate(haystack):
if needle == item:
return idx
return None
index
def find_needle(needle, haystack):
return haystack.index(needle)
These two implementations don't do exactly the same thing - the first will return None if needle isn't found in haystack, where the second will throw a ValueError. I think the former is more forgiving, but it's up to you.

So there are many ways to do this, iteratively and recursively but to take the OP's code as is and what I think they were attempting.
Note: it is generally considered bad practice to use global variables, you should pass the list of numbers and the number to find to the function.
Note: your while loop is effectively implementing a for loop - for counter in range(len(numbers)): would provide the same result
numbers = [24, 10, 92, 28, 71, 1, 80, 70]
number_to_find = 1
def my_loop():
counter = 0
while counter < len(numbers):
if numbers[counter] == number_to_find:
print "Number found at position", counter
else:
print "Counter not found in position" , counter
counter = counter + 1
my_loop()
Output:
Counter not found in position 0
Counter not found in position 1
Counter not found in position 2
Counter not found in position 3
Counter not found in position 4
Number found at position 5
Counter not found in position 6
Counter not found in position 7
Doing the same thing with a for loop:
for counter in range(len(numbers)):
if numbers[counter] == number_to_find:
print "Number found at position", counter
else:
print "Counter not found in position" , counter
Would output the same.
However, perhaps a more idiomatic approach for Python would be to use enumerate:
for counter, number in enumerate(numbers):
if number == number_to_find:
print "Number found at position", counter
else:
print "Counter not found in position" , counter

To find first occurence use numbers.index(x) where x is the number you are searching or for all of them indices = [idx for idx, number in enumerate(numbers) if elem_list == x]

For starters, I think you mean for your else block to correspond to the if. Right now it's associated with the while. Indent the else so it's aligned with the if, and then indent the three lines after the else to align with the print after the if:
if numbers[counter] == number_to_find:
print "Number found at position", counter
else:
print "Counter not found in position" , counter
counter = counter + 1
my_loop()
Once you fix that, your second problem will be that your program will exit immediately because your while condition evaluates to 0 > 6, which is false, so the if block will never even run. Minimally you'll want to change the > to <. At that point, your code will mostly work like you expect it to, but consider:
The application will go into an infinite loop once it finds the value it's looking for.
A for loop would be much nicer than a while with a counter.
You should really avoid using global variables if at all possible (it's very possible here).

Related

Binary search in Python results in an infinite loop

list = [27 , 39 , 56, 73, 3, 43, 15, 98, 21 , 84]
found = False
searchFailed = False
first = 0
last = len(list) - 1
searchValue = int(input("Which number are you looking for? "))
while not found and not searchFailed:
mid = (first + last) // 2
if list[mid] == searchValue:
found = True
else:
if first >= last :
searchFailed = True
else:
if list[mid] > searchValue:
last = mid - 1
else:
last = mid + 1
if found:
print("Your number was found at location", mid)
else:
print("The number does not exist within the list")
The code runs properly when I execute it while searching for 27 (the first number), but any other number just results in an infinite loop.
I believe the loop runs smoothly on the first iteration since if I change the value of first to 1, the code correctly finds the position of 39 but repeats the infinite loop error with all the other numbers after that (while 27 "does not exist within the loop" which makes sense). So I suppose the value of mid is not getting updated properly.
Several points to cover here. First, a binary search needs sorted data in order to work. As your list is not sorted, weirdness and hilarity may ensue :-)
Consider, for example, the unsorted [27 , 39 , 56, 73, 3, 43, 15, 98, 21] when you're looking for 39.
The first midpoint is at value 3 so a binary search will discard the left half entirely (including the 3) since it expects 39to be to the right of that3. Hence it will never find 39`, despite the fact it's in the list.
If your list is unsorted, you're basically stuck with a sequential search.
Second, you should be changing first or last depending on the comparison. You change last in both cases, which won't end well.
Third, it's not usually a good idea to use standard data type names or functions as variable names. Because Python treats classes and functions as first-class objects, you can get into a situation where your bindings break things:
>>> a_tuple = (1, 2) ; a_tuple
(1, 2)
>>> list(a_tuple) # Works.
[1, 2]
>>> list = list(a_tuple) ; list # Works, unintended consequences.
[1, 2]
>>> another_list = list(a_tuple) # No longer works.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list' object is not callable
Covering those issues, your code would look something like this (slightly reorganised in the process):
my_list = [3, 15, 21, 27, 39, 43, 56, 73, 84, 98]
found = False
first, last = 0, len(my_list) - 1
searchValue = int(input("Which number are you looking for? "))
while not found:
if first > last:
break
mid = (first + last) // 2
if my_list[mid] == searchValue:
found = True
else:
if my_list[mid] > searchValue:
last = mid - 1
else:
first = mid + 1
if found:
print("Your number was found at location", mid)
else:
print("The number does not exist within the list")
That works, according to the following transcript:
pax> for i in {1..6}; do echo; python prog.py; done
Which number are you looking for? 3
Your number was found at location 0
Which number are you looking for? 39
Your number was found at location 4
Which number are you looking for? 98
Your number was found at location 9
Which number are you looking for? 1
The number does not exist within the list
Which number are you looking for? 40
The number does not exist within the list
Which number are you looking for? 99
The number does not exist within the list
First of all, do not use any reserved word (here list) to name your variables. Secondly, you have a logical error in the following lines:
if list[mid] > searchValue:
last = mid - 1
else:
last = mid + 1
In the last line of the above snippet, it should be first = mid + 1
There are very good answers to this question, also you can consider this simpler version adapted to your case:
my_list = [3, 15, 21, 27, 39, 43, 56, 73, 84, 98] # sorted!
left, right = 0, len(my_list) # [left, right)
search_value = int(input("Which number are you looking for? "))
while left + 1 < right:
mid = (left + right) // 2
if my_list[mid] <= search_value:
left = mid
else:
right = mid
if my_list[left] == search_value: # found!
print("Your number was found at location", left)
else:
print("The number does not exist within the list")
The problem with your function is that in Binary Search the array or the list needs to be SORTED because it's one of the most important principal of binary search, i made same function working correctly for you
#low is the first index and high is the last index, val is the value to find, list_ is the list, you can leave low as it is
def binary_search(list_: list, val,high: int, low: int = 0):
mid = (low+high)//2
if list_[mid] == val:
return mid
elif list_[mid] <= val:
return binary_search(list_, val, high+1)
elif list_[mid] >= val:
return binary_search(list_, val, high, low-1)
and now here's the output
>>> binary_search(list_, 21, len(list_)-1)
>>> 2
what will happen here is that first it will calculate the middle index of the list, which i think of your list is 5, then it will check whether the middle value is equal to the value given to search, and then return the mid index, and if the mid index is smaller than the value, then we will tell it to add one to high index, and we did the comparison with index and value because as i told you, list needs to be sorted and this means if index is greater or equal to the mid index then the value is also surely greater than the middle value, so now what we will do is that we will call the same function again but this time with a higher high which will increase the mid point and if this time middle index is equal to value, then its gonna return the value and going to do this untill mid is equal to value, and in the last elif it says if middle value is greater than value, we will call same function again but lower the low i.e which is 0 and now -1, which will reduce the mid point and this whole process will continue untill mid is equal to value

Python recursive sequence related code

I am trying to make a code that produces numbers according to the following formula...
T[n] = 1 + T[n-1] * 2
numList = []
numLisst.append (1)
#Begins with a term 1.
def numSequence ():
while True:
for i in range (1,12):
#Temporally set numbers from 1 to 12
numList[i] == 1+(numList[i-1]*2)
break
print (numList)
numSequence()
First of all, this brings an error, list index out of index
I'd like to see this code produce the fibonacci sequences, for example,,
1, 3, 7, 15, 31, 63, 127 , ....
I hope if I use this recursive program, I would be able to find out specific order of the numbers in an array,
e.g. If I'd like to find out 3rd number in the array, should be whether 7 or 15 (It would depend how I would set it)
The recursive implementation of your formula would be the following, assuming your base case was T(1) = 1
def T(n):
if n == 1:
return 1
else:
return 1 + T(n-1)*2
Some examples
>>> [T(i) for i in range(1,10)]
[1, 3, 7, 15, 31, 63, 127, 255, 511]
>>> T(15)
32767
One way to solve this probem (not most Pythonic implementation, though...)
# T[n] = 1 + T[n-1] * 2
def nextFibonachi(n,i):
n = 1 + n*2
print(str(i)+": "+str(n))
return n,i
fibArr = []
for i in range(0,100):
if i == 0:
n = 0
n,i = nextFibonachi(n, i)
fibArr.append(n)
print(fibArr)
m = 10
print("\n"+str(m)+": "+str(fibArr[m]))

Working with empty lists

Okay so I am trying to create an empty list, then add integers to the list to then pick out the highest,lowest and 5 middle numbers( in descending order using a slice) and put them on display... seems simple enough....
def main():
nums = []
for i in range(20,80,9):
nums.append(i)
print(*nums,sep=' ')
print('The highest number is',max(nums))
print('The lowest number is',min(nums))
print('The middle 5 sorted high to low:')
nums.sort()
nums.reverse()
print (*nums[1:6])
main()
Okay so i edited it using your suggestions and the program works fine..... I just cant wrap my head around that damned while loop.... Can anyone see how I could integrate that?
while nums.append(i):. list.append returns None, and None does not evaluate to true. So your print statements will never be executed.
nums.reverse[2:6] reverse is a method and reverses the list in place. It does not return anything. So this part will throw a TypeError. You want to instead call nums.reverse()
The reverse method does not sort. You need nums.sort()
nums[2:6] will get you the elements from index 2 to 6 (exclusive). So this will only get you 4 elements. Additionally, your list has 9 elements (7 if you exclude the min and max). The middle 5 elements would not be between index 2 and 6.
Python has a help() function, use it if you need to know what functions/methods return.
You could refactor your code to use a while loop like so.
def main():
nums = []
i = 20
while i < 80:
nums.append(i)
print(*nums,sep=' ')
i += 9
print('The highest number is',max(nums))
print('The lowest number is',min(nums))
print('The middle 5 sorted high to low:')
# removed on the basis that they are already sorted
#nums.sort()
nums.reverse()
print (*nums[1:6])
main()
It's just a lot nicer using range as you don't need to the i variable outside the scope of the loop.
This is one way to do it:
nums = []
for i in range(20,80,7):
nums.append(i)
mx = max(nums)
mn = min(nums)
nums.remove(mx)
nums.remove(mn)
mx2 = max(nums)
mn2 = min(nums)
nums.remove(mx2)
nums.remove(mn2)
nums.sort()
nums.reverse()
print nums
The output is the 5 middle numbers in descending order:
[62, 55, 48, 41, 34]
and the better, shorter way to do it is this:
def main():
nums = []
for i in range(20,80,7):
nums.append(i)
mx = max(nums)
mn = min(nums)
print "The highest number is %s " % mx
print "The lowest number is %s " % mn
while len(nums) != 5:
nums.remove(max(nums))
nums.remove(min(nums))
nums.sort()
nums.reverse()
print "The middle 5 sorted high to low is %s:" % nums
main()
The output is:
The highest number is 76
The lowest number is 20
The middle 5 sorted high to low is [62, 55, 48, 41, 34]

String Index Out of Range Error in Python

I keep getting an "IndexError: string index out of range" error message when I try to execute this code:
#function countLetters(word,letter) should count the number of times
#a particular letter appears in a word.
def countLetters(word, letter):
count=0
wordlen=len(word)
num=0
wordletter=""
while(num<=wordlen):
wordletter=word[num]
if(wordletter==letter):
count=count+1
num=num+1
return count
print(countLetters("banana", "x"))#should print 0
print(countLetters("banana", "a"))#should print 3
print(countLetters("banana", "b"))#should print 1
The Error Message:
Traceback (most recent call last):
File "C:\Users\Charlie Chiang\Desktop\9G.py", line 17, in <module>
print(countLetters("banana", "x"))
File "C:\Users\Charlie Chiang\Desktop\9G.py", line 10, in countLetters
var=word[num]
IndexError: string index out of range
You take it one index too far:
while(num<=wordlen):
num must stay strictly below the length:
while num < wordlen:
because Python sequences are 0-based. A string of length 5 has indices 0, 1, 2, 3, and 4, not 5.
You are reaching one index too far:
while(num<=wordlen):
For a text "a" the len("a") is 1 and last letter can be reached by index 0. Your while condition allows trying index 1, which is not available.
Bonus: counting using Counter
Python stdlib collections provides excellent Counter:
>>> from collections import Counter
>>> Counter("banana").get("x", 0)
0
>>> Counter("banana").get("a", 0)
3
Fixing your code:
def countLetters(word, letter):
count=0
wordlen=len(word)
num=0
wordletter=""
#here, because the index access is 0-based
#you have to test if the num is less than, not less than or equal to length
#last index == len(word) -1
while(num<wordlen):
wordletter=word[num]
if(wordletter==letter):
count=count+1
num=num+1
return count
print(countLetters("banana", "x"))#should print 0
print(countLetters("banana", "a"))#should print 3
print(countLetters("banana", "b"))#should print 1
more elegant way:
str.count method
'banana'.count('x')
'banana'.count('a')
'banana'.count('b')
Because the index of the string starts at zero, the highest valid index will be wordlen-1.
The index start at 0, not 1.
Try changing:
wordletter = word[num-1]

Not understanding why this won't sum up properly

grades = [100, 100, 90, 40, 80, 100, 85, 70, 90, 65, 90, 85, 50.5]
def grades_sum(grades):
sum = 0
for i in grades:
sum += grades[i]
print(grades_sum(grades))
That's my code and I'm trying to understand why I'm getting an out of index traceback.
Iterating over a list will return the item in the list, not the index of the item. The correct code as you have written it would look like this:
def grades_sum(grades):
total = 0
for grade in grades:
total += grade
return total
Of course as others have answered this can be done much more elegant using sum.
If you actually need the index for something else you could use enumerate like this:
def grades_sum(grades):
total = 0
for i, grade in enumerate(grades):
total += grade #or grades[i]
return total
Or if you don't care about retrieving the item at all
def grades_sum(grades):
total = 0
for i in range(len(grades)):
total += grades[i]
return total
You don't need to do grade[i] because you're already referencing the elements in the list - all you need to do it replace that with a plain old i
However, there is already a builtin function for this - sum
print(sum(grades))
for i in grades: iterates over the elements in grades. It doesn't iterate over the indexes.
To fix your code, just use i instead of grades[i].
Don't be afraid of using print statements. They're excellent for debugging code.

Categories

Resources