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....
Related
I have been working on this assignment for about 2 weeks and have nothing done. I am a starter at coding and my teacher is really not helping me with it. She redirects me to her videos that I have to learn from every time and will not directly tell or help me on how I can do it. Here are the instructions to the assignment (said in a video, but made it into text.
Find the mean
Create a program that finds the mean of a list of numbers.
Iterate through it, and instead of printing each item, you want to add them together.
Create a new variable inside of that, that takes the grand total when you add things together,
And then you have to divide it by the length of your array, for python/java script you’ll need to use the method that lets you know the length of your list.
Bonus point for kids who can find the median, to do that you need to sort your list and then you need to remove items from the right and the left until you only have one left
All you’re doing is you need to create a variable that is your list
Create another variable that is a empty one at the moment and be a number
Iterate through your list and add each of the numbers to the variable you created
Then divide the number by the number of items that you had in the list.
Here's what I've done so far.
num = [1, 2, 3, 4, 5, 6];
total = 0;
total = (num[0] + total)
total = (num[1] + total)
total = (num[2] + total)
total = (num[3] + total)
total = (num[4] + total)
total = (num[5] + total)
print(total)
However, she tells me I need to shorten down the total = (num[_] + total) parts into a loop. Here is how she is telling me to do a loop in one of her videos.
for x in ____: print(x)
or
for x in range(len(___)): print (x+1, ____[x])
there is also
while i < len(___):
print(___[i])
i = i + 1
I really don't understand how to do this so explain it like I'm a total noob.
First of all, loops in python are of two types.
while: a while loop executes the code in a body until a condition is true. For example:
i = 0
while(i < 5):
i = i + 1
executes i = i + 1 until i < 5 is true, meaning that when i will be equal to 5 the loop will terminate because its condition becomes false.
for: a for loop in python iterates over the items of any sequence, from the first to the last, and execute its body at each iteration.
Note: in both cases, by loop body I mean the indented code, in the example above the body is i = i + 5.
Iterating over a list. You can iterate over a list:
Using an index
As each position of the array is indexed with a positive number from 0 to the length of the array minus 1, you can access the positions of the array with an incremental index. So, for example:
i = 0
while i < len(arr):
print(arr[i])
i = i + 1
will access arr[0] in the first iteration, arr[1] in the second iteration and so on, up to arr[len(arr)-1] in the last iteration. Then, when i is further incremented, i = len(arr) and so the condition in the while loop (i < arr[i]) becomes false. So the loop is broken.
Using an iterator
I won't go in the details of how an iterator works under the surface since it may be too much to absorb for a beginner. However, what matters to you is the following. In Python you can use an iterator to write the condition of a for loop, as your teacher showed you in the example:
for x in arr:
print(x)
An iterator is intuitively an object that iterates over something that has the characteristic of being "iterable". Lists are not the only iterable elements in python, however they are probably the most important to know. Using an iterator on a list allows you to access in order all the elements of the list. The value of the element of the list is stored in the variable x at each iteration. Therefore:
iter 1: x = arr[0]
iter 2: x = arr[1]
...
iter len(arr)-1: x = arr[len(arr)-1]
Once all the elements of the list are accessed, the loop terminates.
Note: in python, the function range(n) creates an "iterable" from 0 to n-1, so the for loop
for i in range(len(arr)):
print(arr[i])
uses an iterator to create the sequence of values stored in i and then i is in turn used on the array arr to access its elements positionally.
Summing the elements. If you understand what I explained to you, it should be straightforward to write a loop to sum all the elements of a list. You initialize a variable sum=0 before the loop. Then, you add the element accessed as we saw above at each iteration to the variable sum. It will be something like:
sum = 0
for x in arr:
sum = sum + x
I will let you write an equivalent code with the other two methods I showed you and do the other points of the assignment by yourself. I am sure that once you'll understand how it works you'll be fine. I hope to have answered your question.
She wants you to loop through the list.
Python is really nice makes this easier than other languages.
I have an example below that is close to what you need but I do not want to do your homework for you.
listName = [4,8,4,7,84]
for currentListValue in listName:
#Do your calculating here...
#Example: tempVar = tempVar + (currentListValue * 2)
as mentioned in the comments w3schools is a good reference for python.
Found that the control never reaches the inner while loop in this snippet for deleting a duplicate number
numbers=[1,6,6,7]
k=len(numbers)
i=0
j=0
while i in range(k-1):
while j in range(i+1,k):
if numbers[i] == numbers[j]:
numbers.remove(numbers[j])
k-=1
j-=1
j += 1
i += 1
print(numbers)
Your code does not make j start at i+1. Instead it starts at zero and never changes. The inner loop never runs because 0 is outside of the range you are testing.
Try this simple change:
i=0
while i < k+1:
j=i+1
while j < k:
if numbers[i] == numbers[j]:
...
The main change is moving the initialization of j inside the first while loop, so it updates each time you go through it, and never starts out less than or equal to i.
The other change I made is much less important. Rather than using i in range(...) and j in range(...) for the while loop conditions, I just did an inequality test. This is exactly the same as what the range membership test does under the covers, but avoids unnecessary testing for things that can't happen (like j being too small, now). It also makes the loop look a lot less like a for loop, which uses for i in range(...) syntax a lot (with a different meaning).
Another issue you may run into later, with some sets with multiple sets of duplicates is that your code to remove the jth element probably doesn't do what you intend. The call numbers.remove(numbers[j]) removes the first value equal to numbers[j] from the list, which is going to be the one at index i rather than the one at index j. To delete a list item by index, you want to use del numbers[j].
It doesn't reach because j and i starts at 0 value and in the inner while loop the condition is j in range(i+1, k) which means range(1, 4) and 0 in range(1, 4) would be False. Anyways, you should avoid using j and i as counters and use a for loop instead.
But the solution is easier and doesn't need to traverse the list, if you wanna remove the duplicate values, you can do as below:
numbers = [1, 6, 6, 7]
print(list(set(numbers)))
The result is: [1, 6, 7]
You could remove duplicates from a list in Python by using the dict.fromkeys().
numbers=[1,6,6,7]
final_numbers = list(dict.fromkeys(numbers))
print(final_numbers)
In this example, we use the dict.fromkeys() method to create a dictionary from numbers variable. We then use list() to convert our data from a dictionary back to a list. Then, on the final line, we print out our revised list.
Another option is to use set.
Sets are used to store collections of unique items in Python. Unlike lists, sets cannot store duplicate values.
We can convert our list to a set to remove duplicated items.
numbers=[1,6,6,7]
final_numbers = list(set(numbers))
print(final_numbers)
Write a func/on first_neg that takes a (possibly empty) list of
numbers as input parameter, finds the first occurrence of a
nega/ve number, and returns the index (i.e. the posi/on in the
list) of that number. If the list contains no nega/ve numbers or it
is empty, the program should return None. Use while loop (and
not for loop) and your while loop should stop looping once the
first nega/ve number is found.
This is the question my teacher asked me any ideas this what i did:
def first_neg(list):
count = 0
for number in list:
if number < 0:
count += 1
return count
Dosent seem to work properly i just joined 1st post hope can get some help
x = [1,2,3,-5]
def first_neg(list):
count = 0
for number in list:
count += 1 #moved it outside of the if
if number < 0:
return count
print(first_neg(x)) #prints 4
You want to increment count not when you've found the answer but everytime the forloops loops. Note that this method returns 4 which is the fourth item in the list, not the index, Index of the list starts from 0 so to access it would be 3. Take our list x = [1,2,3,-5], -5 is in the fourth slot of the list, but to access it we have to call x[3] since lists starts at 0 indexing.
If you want to return the index of the list where the first negative number is found try this:
x = [1,2,3,-5]
def first_neg(list):
for count, number in enumerate(list):
if number < 0:
return count
print(first_neg(x)) # prints 3
This is because enumerate creates a "pairing" of the item in the list and it's the current count. Enumerate just counts from 0 everytime it gets an item out of the list.
Also as a side note ( I didn't change it in my answer since I wanted you to understand what's going on ). Don't name your variables keywords like list, tuple, int, str... Just a bad idea and habit, it works as you can see but it can cause issues.
Return the index immediately once you encounter the negative element. Increment the index otherwise:
def first_neg(lst):
count = 0
while count < len(lst):
if lst[count] < 0:
return count
count = count + 1
return None
Note : Better if you use enumerate() rather than using extra count variable. The code you mentioned is not written in pythonic way.
You may try this as well:
def first_neg(lst):
res = [i for i,x in enumerate(lst) if x<0]
return None if res == [] else res[0]
The code above can be improved using generators as suggested by #Chris_Rands.
rmNegative(L) removes the negative numbers from list L, assumed to contain only numeric elements. (Modifies L; does not create a new list.)
How would I go about this when using a while loop? I've tried coding it over and over and all I got was a never ending loop..
def rmNegatives(L):
pos=len(L)-1
while pos>-1:
pos=pos
if pos<len(L)-1:
pos=pos
if L[pos]>0:
L[:]=L[:]
pos=len(L)-2
elif L[pos]<0:
L[:]=[L[pos]]+L[0:]
L[:]=L[1:]
pos=len(L)-1
elif pos==len(L)-1:
pos=pos
if L[pos]<0:
L[0:]=L[0:pos]
pos=len(L)-1
elif L[pos]>0:
L[:]=L[:]
pos=len(L)-2
rmNegatives([-25,31,-10,23,45,-2])
Run the code here
edit** i thank you for your responses. the reason why my code does not contain any form of remove or index is because i was restricted from using them(would have been nice if they weren't but..)
Here is an implementation with a while loop. I start at the end because the list is getting shorter as the loop iterates and the earlier indexes are shifting as a result.
def rmNegative(L):
index = len(L) - 1
while index >= 0:
if L[index] < 0:
del L[index]
index = index - 1
If you absolutely cannot afford to create a new list and you have to use a while loop:
l = [1,2,3,-1,-2,-3,4,5]
x = 0
while x < len(l):
if l[x] < 0:
l.remove(l[x])
continue
x += 1
Alternatively, as suggested by abarnert (lower runtime):
l = [1,2,3,-1,-2,-3,4,5]
x = 0
while x < len(l):
if l[x] < 0:
del l[x]
continue
x += 1
If you absolutely cannot afford to create a new list, but can use a for loop:
l = [1,2,3,-1,-2,-3,4,5]
for x in xrange(len(l)):
if x < len(l) and l[x] < 0:
l.remove(l[x])
If you can afford to create a new list:
l = [1,2,3,-1,-2,-3,4,5]
l = [num for num in l if num >= 0]
Code:
def rmNegatives(L):
i = 0
while i < len(L):
if L[i] < 0:
L.pop(i)
else:
i += 1
return L
The first think you need to know is that del L[i] removes the ith element. (Don't use L.remove(L[i]); that looks up the ith element, then searches the whole list until it finds an equal value, then deletes that.)
But notice that if you delete L[3], and then move on to L[4], you've skipped one value—the original L[4] is now L[3], and you still need to check it. So you have to make sure not to increment i until you find a value that you're keeping.
But if you just loop over all of the indices, and you've deleted some along the way, you're going to run off the end. So, you need to decrement the the length every time you delete. Or you could also just keep calling len(L) again and checking against the new length each time.
One clever way to solve both of those problems at once is to count backward, as in Brad Budlong's answer. But that can make it easy to make fencepost errors. So, I'll do it the other way.
def rmNegative(L):
length = len(L)
i = 0
while i < length:
if L[i] < 0:
del L[i]
length -= 1
else:
i += 1
And that's it.
If you want to know why your existing code is an infinite loop, let's step through a bit of what it does.
We start with pos=len(L)-1, so we go into the big elif. pos=pos does nothing. If it's a negative number, you remove it and go to the new len(L)-1; if it's a positive number, you leave it, and go to len(L)-2. If it's 0, we do neither, which means pos=len(L)-1 still, and we're just going to repeatedly look at that 0 forever.
So, that's one way to get an infinite loop. But let's assume it didn't end in 0.
If we've just removed a negative number, we go back to the elif, and we know that's OK unless 0.
But if we've left a positive number, then we now have pos=len(L)-2, so we go to the if. Again, pos=pos does nothing. If it's a positive number, we copy the list to itself, which does nothing, then set pos=len(L)-2. Which is the same thing it already is. So, if the next-to-last number is positive, we're just going to keep looking at that number forever. That's another way to get an infinite loop.
What if it was negative? Then L[:]=[L[pos]]+L[0:] prepends the value you wanted to delete to the whole list (which still includes the original copy of the value), L[:]=L[1:] removes the value you just prepended, so you end up with the same values in L you started with. Then you set pos=len(L)-1, which goes back to the end of the list. We know that's going to work successfully, and get back to the next-to-last slot again, which will still be the same value, so we'll shuttle back and forth forever. So, that's enough way to get an infinite loop.
What if it was 0? Then we do nothing, so pos and L never change, so that's another way to get an infinite loop.
So, once we get a positive element on the end of the list, all three possibilities for the next-to-last element are infinite loops.
Stepping back a bit, the only things your code ever sets pos to are len(L)-1 and len(L)-2. So, even if you did all of the others stuff right, how could this possibly ever complete on a list with more than 2 non-negative numbers?
Here is my implementation of rmNegative(L).
def rmNegative(L):
m = min(L)
while m < 0:
L.remove(m)
m = min(L)
This modifies the list and does not create a new list.
Well, not allocating new list now,
>>> list_l = [1, -1, 2, -8]
>>> length = len(list_l)
>>> while i < length:
... if list_l[i] < 0:
... del list_l[i]
... length -= 1
... else:
... i = i + 1
...
>>> list_l
[1, 2]
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.