Loop in a list (Python v3) beginner - python

I am stuck in making a loop that will eliminate the values(from the alist) that are below average.
Thanks for the help.
a=input("Enter a list of values separated by a coma : ")
alist=eval(a)
print("the list is : ",alist)
average = sum(alist)/len(alist)
print("the average is : ",average)
for i in alist:
if alist[i]<average:
alist.remove[i]

You are almost there. Instead of removing elements, select elements you want to retain instead:
alist = [a for a in alist if a>=average]
Your mistake here is that for i in alist: is iterating over list elements themselves, not indexes, so alist[i] is throwing an error (or returning nonsense).

For the "loop" you can use a filter and a lambda function.
above_average = list(filter(lambda x: x >= average, alist))
For the rest of your code, I suggest you clean it up to something which is safer (use of eval is very bad)
import ast
user_string = raw_input('input a list of numbers separated by a commas: ')
alist = list(ast.literal_eval(user_string)))
So, in all, I would write your code as something like this:
import ast
user_string = raw_input('input a list of numbers separated by a commas: ')
numbers = list(ast.literal_eval(user_string)))
average = sum(numbers)/len(numbers)
print('The numbers: {}'.format(numbers))
print('The average: {}'.format(average))
above_average = list(filter(lambda x: x >= average, numbers))
# now do what you want with the above_average numbers.

Other answers tell you how to do it. I'll tell you why it doesn't work:
You iterate over the list and, at the same time, modify it.
This leads to items being missed during the iteration.
Why?
Internally, the iteration works via an index to the list. So it is the same as doing
idx = 0
while True:
try:
i = alist[idx]
except IndexError:
break
idx += 1
if alist[i] < average:
alist.remove(i)
What happens if you are at the element #3, go to the next one and then remove #3? Right, the indexes of the remaining ones move down and you are pointing to the one which formerly was #5. The old #4 is skipped at this test.
(BTW, I don't know if you noticed, I have replaced your [] behind .remove with ().)

You are mixing two ways of iterating a list: By index, and by element. In your loop, i is not the index, but the element of the list itself, thus alist[i] won't work.
If you use the for x in somelist loop, then x is the element itself, not the index of the element. For iterating over the indices, you can use for i in range(len(somelist)), or you could use for i, x in enumerate(somelist) to loop over tuples of index and element.
Also note that removing elements from a list or other kinds of collections while you are looping them generally is a bad idea. Better create a copy of the list.
for x in list(alist): # creates a copy of alist
if x < average: # remember: x is the element itselt
alist.remove(x) # remove element x from list
But the way you do it (with eval of a comma-separated string of numbers), alist is a tuple, not a list, and thus has no remove method at all. Thus you either have to convert it to a list before (alist = list(eval(a)), or use one of the approaches given in the other answers, creating a new list using list comprehension or filter and retaining the "good" elements.

As a general principle for asking StackOverflow questions like this, you should always include example input and output -- show what happens, and what you expect to happen.
In this case, I believe there are two three problems with your code:
Edit: Third, but possibly most importantly, look at glglgl's answer. If you implement the two fixes I describe below, you'll still have one problem: your code won't necessarily remove all the items you want to remove, because it'll skip over some items.
First, you say alist[i], which grabs the element of alist at index i. But saying for i in alist makes i be successive elements in the list already. Example:
mylist = [1, 2, 4]
for i in mylist:
print(i)
Would give you the output:
1
2
4
If you instead said this (which is like what you wrote)
mylist = [1, 2, 4]
for i in mylist:
print(mylist[i])
It wouldn't work as you'd expect, because you'd get the element at index 1, the element at index 2, and then try to get the element at index 4, but that wouldn't exist. You'll get something like this:
2
4
IndexError: list index out of range
Second, your syntax for removing an element is wrong. You should use alist.remove(i) instead of alist.remove[i]. You want to call a function, so you use parentheses. The square brackets are for indexing and slicing.

Related

Remove a list while iterating in python without copying to new list

I want to remove elements from my list while iterating the list. I don't think copying the list and performing the operations on either one will solve my problem.
I have a nested list,
Here as soon as I get the leftmost or the rightmost values of the list == maximum I append it to a new list Lst1 and pop the element from the original list else break from the loop.
lst= [[4, 3, 2, 1, 3, 5]]
lst1=[]
for i in range(len(lst)):
if lst[0][i]==max(lst[0]):
lst1.append(lst[0][i])
lst.remove(lst[0][i])
elif lst[0][maxsize_lst-1]==max(lst[0]):
lst1.append(lst[0][maxsize_lst-1])
lst.remove(lst[0][maxsize_lst-1])
else :
print("NO")
break;
I'm getting the below errors and sometimes I get index out of range probably because i'm removing the element and iterating the list again
ValueError: list.remove(x): x not in list
The output of list 1 should look something like:
5 4 3 3 2 1
EDIT
The final list is coming in the descending order but it's not a sorting problem. Here i will be first picking either the leftmost or rightmost element first and check if it is == max(lst). if any of them follows true i'm removing that element.Now my list would be having one less element. If it was leftmost pop then i would resume from index 1 to last ,vice versa if it was rightmost i would again do the same search from index 0 to maxsize-2 to do the same search. If nothing follows like leftmost or rightmost != Max(lst) then break and print No
There is a much simple solution:
lst = [[4, 3, 2, 1, 3, 5]]
print(sorted(lst[0], reverse=True))
Result:
[5, 4, 3, 3, 2, 1]
First of all, you want to remove values from your nested list at the level where they are: lst.remove(x) only searches in lst, not in lst and all possible lists nested in lst. That will solve your problem with ValueError.
Second, simply running your example by hand tells you why it isn't working: you are never updating maxsize_lst, therefore as soon as you pop out an item this value is no longer valid. A simple solution would be to use python's negative indexing system to access the last value of your list: lst[-1]. But even then, if your goal is to get all values in your list sorted, your code cannot do it: on the first step of your example already,
with i=0, you remove 5 from the list (last item, max of values)
next step, i=1, and you will never again access the value at i=0
But then maybe that's not a problem for you, it isn't clear what you want to achieve with your code...
Edit: I re-read your question, if what you want is actually to pop the left/rightmost value when it is a maximum from your old list to your new list, then you shouldn't be iterating over your list with a for loop but rather using a while loop like that:
size_lst = len(lst[0])
while size_lst > 0:
if lst[0][0] == max(lst[0]):
# Leftmost element max of the list
lst1.append(lst[0].pop(0) # Pop leftmost element of lst[0] into lst1
size_lst -= 1 # Record that you decreased the size of your list
elif lst[0][-1] == max(lst[0]):
# Same with the rightmost element
lst1.append(lst[0].pop(-1)
size_lst -= 1
else:
break
It looks like you're sorting the first list. This can be achieved much more easily. The sorted function will automatically sort it from least to greatest, and then you can use the reversed function to sort greatest to least. Try:
lst1 = reversed(sorted(lst[0]))
EDIT: If you need to use the method put forward in the original code, I caught a mistake in your for loop. You are taking the length of lst, not the sublist, the code should be the following:
for i in range(len(lst[0])):
Also, I don't know if you established a variable maxsize_list, but you can get the last element of the list easily with lst[0][-1]. Finally, your error is being caused by you trying to remove lst[0][-1] from lst, not lst[0]. This is your code without syntax errors. I believe there is a symantic error that occurs when the maximum is at the end.
lst= [[4,3,2,1,3,5]]
lst1=[]
for i in range(len(lst[0])):
if lst[0][i]==max(lst[0]):
lst1.append(lst[0][i])
lst[0].remove(lst[0][i])
elif lst[0][-1]==max(lst[0]):
lst1.append(lst[0][-1])
lst[0].remove(lst[0][-1])
else :
print("NO")
break;
#PRMoureu's comment is a big hint to the answer about what's going wrong.
In your sample data, your list is of size 6. You're iterating over the indices, so from 0 through 5. As you progress through your loop, you remove things from your list, but then you continue to look for it. So at some point, you look at lst[0][i] for an i that no longer exists, and that's why you get your error. This will happen as long as you're using the index.
But you don't need the index into the list. You need the value at it. So the recommendation is a very good idea: simply iterate on the list itself, instead of on its indices. This will give you code like this:
lst= [[4, 3, 2, 1, 3, 5]]
lst1=[]
for val in lst[0]:
print(val)
if val == max(lst[0]):
print("a")
lst1.append(val)
lst[0].remove(val)
print(lst[0])
# this shouldn't even be necessary; you should be able to sort just as well without it
elif lst[0][-1]==max(lst[0]):
print("b")
lst1.append(lst[0][-1])
lst[0].remove(lst[0][-1])
else :
print("NO")
break;
Note, python wouldn't use a construct like maxsize_lst. Instead, it would just use lst[0][-1] to get the last element. I fixed the several places where you were referring to lst instead of lst[0], and made your lst definition actually be valid by putting commas between the values.
When I run this code, I get "NO" as a result. Leave the print statements in to understand why. The first time, you have a 4. It isn't the max, so you look to see if the last value is a max. It is, so it gets added. The second time, you have a three, which is again not your max. Nor is the last remaining value (the other 3), so it says "NO" and aborts. You've got the idea by using a break statement, but you need another loop around it that would continue until your list is empty.
To get this to work, you need an outer loop similar to as follows:
lst= [[4, 3, 2, 1, 3, 5]]
lst1=[]
reset = True
while len(lst[0]) != 0 and reset:
print(lst[0], lst1)
reset = False
for val in lst[0]:
print(val)
if val == max(lst[0]):
print("a")
lst1.append(val)
lst[0].remove(val)
reset = True
break
elif lst[0][-1]==max(lst[0]):
print("b")
lst1.append(lst[0][-1])
lst[0].remove(lst[0][-1])
reset = True
break
else :
print("NO")
break
Note that I did need to add a break even when popping from the left side. Without that, the end result was that lst1 had a value of [5, 4, 3, 3, 2], and lst[0] still had [1] in it.

Removing n multiple items from a list

Question
I want to remove items from a list such that I keep the first n items, and remove the next 2n items.
For example
for n=8, I want to keep the first 8, remove the next 16 and repeat this as necessary:
a = range(48)
Which I want to become
[0,1,2,3,4,5,6,7,24,25,26,27,28,29,30,31]
This is to pick out the first 8 hours of a day, and run a function on each hour.
I've found it hard to phrase this in search queries so the answer is probably simple but I've had no luck!
You could just use a comprehension list:
[ a[i] for i in range(len(a)) if (i % 24 < 8) ]
The above only create a new list. If you want to edit the list in place, you must explicitely delete unwanted elements, starting from the end to avoid changing indexes:
for i in range(len(a) - 1, 0, -1):
if i % 24 >= 8:
del a[i]
def hours(n):
items = [x for x in range(49)]
del items[n:n*3]
print(items)
hours(8)
Depending on how new you are you might have a hard time understanding this code, so I will try to explain a little:
We start by creating a function which takes a parameter n which, for test purposes, we will be using 8 then we use a list comprehension to generate all our numbers (0, 48) and then delete the unneeded elements using the del statement, we are deleting from the nth to the n*3 element in the list. For example, if n were to be passed as 9 our use of the del statement could be translated as: del [9:27].
Hope this makes sense.
This should be quite easy to understand
a = range(48)
n=8
result=[]
while a:
result+= a[:n]
a=a[n*3:]
print result

Facing an issue in removing duplicate entries in a list of my python Program

The below program is for entering the values to a list and print the list again after removing the duplicate entries... Can someone please have a look and let me know what would be the error in the program?
print ("Enter the Numbers into List \n")
list = []
n = int(input(""))
while n <= 1000:
list.append(n)
n = int(input(""))
m = len(list)
for i in range (0,m-1):
for j in range (i+1,m):
if list[i] == list[j]:
list.remove(j)
else:
pass
print (list)
When I run the program it gives below error:
File "python", line 23, in <module>
ValueError: list.remove(x): x not in list
There are several problems with your code.
The first is your assumption that list.remove() takes an index as its argument. It doesn't remove an element by index, but by value (see the method's documentation). The second is that if you modify a list as you iterate over it you may well find that this messes up your indexing:
>>> for i in range(len(lst)):
... if i == 2:
... del lst[i]
... else:
... print(lst[i])
...
1
2
Traceback (most recent call last):
File "<stdin>", line 5, in <module>
IndexError: list index out of range
The third (minor) issue is that you are using the name of a built-in type (list) as a variable in your code, which will "shadow" the built-in type, making it inaccessible.
There are a number of problems in your solution:
The one you run into is that the remove method removes the first element that matches the argument, but you use the index of the element as argument which does not need to be one of the element. Instead if you want to remove an element by index you should use del mylist[index] instead.
Second you're trying to modify an list while iterating through it and that's not a good thing, you will probably not getting the result from that that you expect.
Also a aestetically questionable construct is calling your list list, that name is already used by the type list. By doing so you run into the problem that you can't use the builtin list anymore and that could be confusing.
The pythonic way to do this is to use the library functions and not reinventing the wheel (and of course not calling your list list):
import collections
mylist[:] = list(collections.OrderedDict.fromkeys(mylist).keys())
What it does is using OrderedDict which retains the order of the keys to put the element into and then create a list from that and then put it in the original list.
That solution however assumes that the items are hashable, which might not be the case. Otherwise the only solution is to iterate twice through the list as Cunningham's answer shows (which is therefore slower).
You are trying to remove j not what is in list[j], you also need to make a copy of the list and remove from that, when you remove elements you change the size of the list so apart from an index error you will try to remove elements that are not there:
m = len(lst)
out = lst[:]
for i in range(m - 1):
for j in range(i + 1, m-1):
if lst[i] == lst[j]:
out.remove(lst[j])
print(out)
To remove from the original list, you can use a set and reversed:
seen = set()
for ele in reversed(lst):
if ele in seen:
lst.remove(ele)
seen.add(ele)
print(lst)
Or use an OrderedDict:
from collections import OrderedDict
print(list(OrderedDict.fromkeys(lst).keys()))
A simple way using comprehension would be assuming your list name is l to avoid clashing with the type list:
l = [ l[i] for i in range(len(l)) if l[i] not in l[:i] ]
It avoids a name clash with the builtin type list, and modifying a list that you are iterating, and is still O(n2/2)
as you keep deleting the elements the length of list keeps decreasing and the index you are accessing might not be accessible
instead do something like
list(set(t))
and dont name your lists as the "list" keyword

Skip an iteration while looping through a list - Python

Is there a way to skip the first iteration in this for-loop, so that I can put a for-loop inside a for-loop in order to compare the first element in the list with the rest of them.
from collections import Counter
vowelCounter = Counter()
vowelList = {'a','e','i','o','u'}
userString = input("Enter a string ")
displayed = False
for letter in userString:
letter = letter.lower()
if letter in vowelList:
vowelCounter[letter] +=1
for vowelCount1 in vowelCounter.items():
char, count = vowelCount1
for vowelCount2 in vowelCounter.items(STARTING AT 2)
char2, count2 = vowelCount2
if count > count2 : CONDITION
How would the syntax go for this? I only need to do a 5 deep For-loop. So the next would Start at 3, then start at 4, then 5, the the correct print statement depending on the condition.
Thanks
You could do:
for vowelCount2 in vowelCounter.items()[1:]:
This will give you all the elements of vowelCounter.items() except the first one.
The [1:] means you're slicing the list and it means: start at index 1 instead of at index 0. As such you're excluding the first element from the list.
If you want the index to depend on the previous loop you can do:
for i, vowelCount1 in enumerate(vowelCounter.items()):
# ...
for vowelCount2 in vowelCounter.items()[i:]:
# ...
This means you're specifying i as the starting index and it depends on the index of vowelCount1. The function enumerate(mylist) gives you an index and an element of the list each time as you're iterating over mylist.
It looks like what you want is to compare each count to every other count. While you can do what you suggested, a more succinct way might be to use itertools.combinations:
for v1,v2 in itertools.combinations(vowelCounter, 2):
if vowelCounter[v1] > vowelCounter[v2]:
# ...
This will iterate over all pairs of vowels for comparison. Doing it this way, you may also want to check if vowelCounter[v2] > vowelCounter[v1] as you won't see these two again (this goes for this method or the nested for loop method). Or, you can use the itertools.permutations function with the same arguments and just one check would suffice.
To skip an iteration you can use the continue keyword eg:
list = [1,2,3,4,5,6,7,8,9,10]
for value in list:
if value == list[0]:
continue
print(value)
Would give you:
2
3
4
5
6
7
8
9
10
I hope this answers your question.
Slicing a list with [1:] as suggested by a few others creates a new array. It is faster and more economic to use a slice iterator with itertools.islice()
from itertools import islice
for car in islice(cars, 1, None):
# do something

Why does Python skip elements when I modify a list while iterating over it?

I'm currently developing a program in python and I just noticed that something was wrong with the foreach loop in the language, or maybe the list structure. I'll just give a generic example of my problem to simplify, since I get the same erroneous behavior on both my program and my generic example:
x = [1,2,2,2,2]
for i in x:
x.remove(i)
print x
Well, the problem here is simple, I though that this code was supposed to remove all elements from a list. Well, the problem is that after it's execution, I always get 2 remaining elements in the list.
What am I doing wrong? Thanks for all the help in advance.
Edit: I don't want to empty a list, this is just an example...
This is a well-documented behaviour in Python, that you aren't supposed to modify the list being iterated through. Try this instead:
for i in x[:]:
x.remove(i)
The [:] returns a "slice" of x, which happens to contain all its elements, and is thus effectively a copy of x.
When you delete an element, and the for-loop incs to the next index, you then skip an element.
Do it backwards. Or please state your real problem.
I think, broadly speaking, that when you write:
for x in lst:
# loop body goes here
under the hood, python is doing something like this:
i = 0
while i < len(lst):
x = lst[i]
# loop body goes here
i += 1
If you insert lst.remove(x) for the loop body, perhaps then you'll be able to see why you get the result you do?
Essentially, python uses a moving pointer to traverse the list. The pointer starts by pointing at the first element. Then you remove the first element, thus making the second element the new first element. Then the pointer move to the new second – previously third – element. And so on. (it might be clearer if you use [1,2,3,4,5] instead of [1,2,2,2,2] as your sample list)
Why don't you just use:
x = []
It's probably because you're changing the same array that you're iterating over.
Try Chris-Jester Young's answer if you want to clear the array your way.
I know this is an old post with an accepted answer but for those that may still come along...
A few previous answers have indicated it's a bad idea to change an iterable during iteration. But as a way to highlight what is happening...
>>> x=[1,2,3,4,5]
>>> for i in x:
... print i, x.index(i)
... x.remove(i)
... print x
...
1 0
[2, 3, 4, 5]
3 1
[2, 4, 5]
5 2
[2, 4]
Hopefully the visual helps clarify.
I agree with John Fouhy regarding the break condition. Traversing a copy of the list works for the remove() method, as Chris Jester-Young suggested. But if one needs to pop() specific items, then iterating in reverse works, as Erik mentioned, in which case the operation can be done in place. For example:
def r_enumerate(iterable):
"""enumerator for reverse iteration of an iterable"""
enum = enumerate(reversed(iterable))
last = len(iterable)-1
return ((last - i, x) for i,x in enum)
x = [1,2,3,4,5]
y = []
for i,v in r_enumerate(x):
if v != 3:
y.append(x.pop(i))
print 'i=%d, v=%d, x=%s, y=%s' %(i,v,x,y)
or with xrange:
x = [1,2,3,4,5]
y = []
for i in xrange(len(x)-1,-1,-1):
if x[i] != 3:
y.append(x.pop(i))
print 'i=%d, x=%s, y=%s' %(i,x,y)
If you need to filter stuff out of a list it may be a better idea to use list comprehension:
newlist = [x for x in oldlist if x%2]
for instance would filter all even numbers out of an integer list
The list stored in the memory of a computer. This deals with the pointer to a memory artifact. When you remove an element, in a by-element loop, you are then moving the pointer to the next available element in the memory address
You are modifying the memory and iterating thru the same.
The pointer to the element moves through the list to the next spot available.
So in the case of the Size being 5...enter code here
[**0**,1,2,3,4]
remove 0 ---> [1,**2**,3,4] pointer moves to second index.
remove 2 ---> [1,3,**4**] pointer moves to 3rd index.
remove 4 ---> [1,3]
I was just explaining this to my students when they used pop(1). Another very interesting side-effect error.
x=[1,**2**,3,4,5]
for i in x:
x.pop(1)
print(x,i)
[1, **3**, 4, 5] 1 at index 0 it removed the index 1 (2)
[1, **4**, 5] 3 at index 1 it removed the index 1 (3)
[1, 5] 5 at index 2 it removed the index 1 (4)
heh.
They were like why isnt this working... I mean... it did... exactly what you told it to do. Not a mind reader. :)

Categories

Resources