0

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]
Alfie brown
  • 87
  • 2
  • 2
  • 9
  • `eval` should be avoided. See http://stackoverflow.com/questions/1832940/is-using-eval-in-python-a-bad-practice. – jpmc26 Nov 01 '13 at 02:08

5 Answers5

4

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).

sashkello
  • 17,306
  • 24
  • 81
  • 109
3

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.
Inbar Rose
  • 41,843
  • 24
  • 85
  • 131
  • 1
    [`literal_eval`](http://docs.python.org/2/library/ast.html#ast.literal_eval) isn't so evil and might work just as well as `eval` would in this case, which would avoid the `split` and `map` to `int`. – jpmc26 Oct 21 '13 at 09:51
  • 1
    The only way `literal_eval` will convert a string like `"1,2,3,4"` into a list of integers is through magic. You would need to have the string look like `"[1, 2, 3, 4]"` which would mean appending and preppending a square bracket to the start and end of the string. Which would look like this: `alist = ast.literal_eval('[{}]'.format(user_string))` What is wrong with splitting and mapping? – Inbar Rose Oct 21 '13 at 09:57
  • Just tested in Python 2.7. `"1,2,3,4"` becomes a `tuple`. Since `tuple`s are iterable, that shouldn't pose a problem. I assume that syntax carries over into Python 3.x as well. – jpmc26 Oct 21 '13 at 09:58
  • Yes, it would be a tuple, but the the OP is using a list, though I suppose `alist = list(ast.literal_eval(user_string)))` is not so bad. – Inbar Rose Oct 21 '13 at 10:02
  • @InbarRose if you're so keen on datatype corectness, to end up with the same datatype, you need to put a `list()` around the filter expression also. OP is using python 3 and there filter returns an iterator, not a list. – KillianDS Oct 21 '13 at 10:47
2

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.

tobias_k
  • 81,265
  • 12
  • 120
  • 179
2

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 ().)

glglgl
  • 89,107
  • 13
  • 149
  • 217
1

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.

Community
  • 1
  • 1
Pandu
  • 1,606
  • 1
  • 12
  • 23