Python wont remove items from list - python

filtered_list = ['PerezHilton', 'tomCruise', 'q', 'p']
#BIO[user]['follows'] is just a list of strings say ['a', 'b', 'katieh']
#specs is also a string say eg. 'katieh'
for user in filtered_list:
if specs not in BIO[user]['follows']:
filtered_list.remove(user)
The above code for some reson gives this error "ValueError: list.remove(x): x not in list" but clearly 'p' is in the list so why is it not detecting 'p' but it is finding 'q'??
Im soo stumped but any help is appreciated, thanks
** SORRY i FIXED IT NOW *

The list comprehension that does this correctly in one line is at the bottom of the post. Here's some insight into the problem first.
Don't do things like:
for item in list_:
list_.remove(item)
because bad and confusing things happen.
>>> list_ = range(10)
>>> for item in list_:
... list_.remove(item)
...
>>> list_
[1, 3, 5, 7, 9]
Every time you remove an item, you change the indexes for the rest of the items which messes up the loop. One good way to remove items from a list while you're traversing it is to do it by index and work backwards so that removals don't affect the rest of the iterations. This is better because if you remove the 9'th element, then the 8'th element is still the 8'th element but the 10'th element becomes the 9'th element. If you've already dealt with that element, then you don't care what its index is.
>>> list_ = range(10)
>>> for i in xrange(len(list_) - 1, -1, -1):
... del list_[i]
...
>>> list_
[]
Or with a while loop:
i = len(list_)
while i:
i -= 1
del list_[i]
So in your case, the code would look something like
users[:] = [user for user in users if specs in BIO[user]['follows']]
because this is a filtering job and those are best done with list comprehensions. The point of the [:] is that it assigns to a slice of the list instead of clobbering the reference to the list. This means that every other reference to the list will be updated. It's essentially in-place, except that a copy is made before overwriting the original list. For the sake of completeness, here's how to do it with a while loop.
i = len(users)
while i:
i -= 1
if specs not in BIO[users[i]]['follows']:
del users[i]
You could do this if you wanted it done in place. No copy of the list is made here.

Why are you iterating?
>>> un = ['PerezHilton', 'tomCruise', 'q', 'p']
>>> un.remove('p')
>>> un
['PerezHilton', 'tomCruise', 'q']

Related

How to delete all elements only that i want?

I'm really beginer of python and i'm wondering how to remove all same elements that i want
I know i can remove a one element with list.remove('target') but it just happen once,
I googled about it but they just say use 'for' or 'while' but i don't know how to do it with a smart way
example , when i have list "apple" i want to make it "ale" with parameter'p'
I tried
list = ['a','p','p','l','e']
for i in list:
list.remove('p')
but i got error that 'ValueError: list.remove(x): x not in list'
(My English might sucks because i'm Korean :( and it's my first ask in stackoverflow )
First you should not be using list as a variable name as list is a built-in type in python.
See: Built-in types in python
For your question, you can use list comprehension for this.
eg:
my_list = ['a','p','p','l','e']
element_to_remove = 'p'
new_list = [item for item in my_list if item != element_to_remove]
# new_list = ['a', 'l', 'e']
You can convert the list to set (so that there will be no repetitions) and convert it back to list. After, remove the element you want.
my_list = ['a','p','p','l','e']
my_list2 = my_list(set(my_list))
my_list.remove('p')
Try list comprehension:
[i for i in l if i not in ('p',)]
where l is your list.

Iterating over 2 lists at once and comparing the elements

This is just a small part of my homework assignment. What im trying to do is iterate through list1 and iterate backwards through list2 and determine if list2 is a reversed version of list1. Both lists are equal length.
example: list1 = [1,2,3,4] and list2 = [4,3,2,1]. list2 is a reversed version of list1. You could also have list1 = [1,2,1] and list2 = [1,2,1] then they would be the same list and also reversed lists.
Im not asking for exact code, im just not sure how i would code this. Would i run 2 loops? Any tips are appreciated. Just looking for a basic structure/algorithm.
edit: we are not allowed to use any auxiliary lists etc.
You can just iterate backwards on the second list, and keep a counter of items from the start of the first list. If items match, break out of the loop, otherwise keep going.
Here's what it can look like:
def is_reversed(l1, l2):
first = 0
for i in range(len(l2)-1, -1, -1):
if l2[i] != l1[first]:
return False
first += 1
return True
Which Outputs:
>>> is_reversed([1,2,3,4], [4,3,2,1])
True
>>> is_reversed([1,2,3,4], [4,3,2,2])
False
Although it would be easier to just use builtin functions to do this shown in the comments.
The idea here is that whenever you have an element list1[i], you want to compare it to the element list2[-i-1]. As required, the following code creates no auxiliary list in the process.
list1 = [1, 2, 3]
list2 = [3, 2, 1]
are_reversed = True
for i in range(len(list1)):
if list1[i] != list2[-i - 1]:
are_reversed = False
break
I want to point out that the built-in range does not create a new list in Python3, but a range object instead. Although, if you really want to stay away from those as well you can modify the code to use a while-loop.
You can also make this more compact by taking advantage of the built-in function all. The following line instantiate an iterator, so this solution does not create an auxiliary list either.
are_reversed = all(list1[i] == list2[-i - 1] for i in range(len(list2))) # True
If you want to get the N'th value of each list you can do a for loop with
if (len(list1) <= len(list2):
for x in range(0, len(list1):
if (list1[x] == list2[x]):
#Do something
else:
for x in range(0, len(list2):
if (list1[x] == list2[x]):
#Do something
If you want to check if each value of a list with every value of another list you can nestle a for loop
for i in list1:
for j in list2:
if (list1[i] == list2[j]):
//Do something
EDIT: Changed code to Python

Not able to delete string item with colon in python list

So I'm having the following problem while coding in python: I have a few string items in a list like so:
['X','Y','Z','A', 'B:C', 'D']
I want to delete everything past 'Z'. I use the following code to attempt this:
for item in lines:
if ((item == "A")):
lines.remove(item)
if (item == "B:C"):
lines.remove(item)
if (item == "D"):
lines.remove(item)
A and D get removed perfectly. However, B:C is not removed and stays in the list...
Mind you, A, D, B:C etc represent strings, not characters (e.g. A could be Transaction failed! and B:C can represent WRITE failure: cannot be done!)
How can this be solved?
Modifying a list while iterating over it is usually a bad thing. Some of the elements get skipped when you remove the current element. You may be able to fix it by iterating over reversed(lines), but it is better to create a new list that doesn't have the elements that you want to drop:
to_remove = {'A', 'B:C', 'D'}
new_lines = [line for line in lines if line not in to_remove]
Or, if you want to modify in-place:
to_remove = {'A', 'B:C', 'D'}
lines[:] = [line for line in lines if line not in to_remove]
You may use the .index() method to find the index of a specific element inside a list.
Then after finding the z_index, you may create another list by slicing the first one.
Here's an example:
l1 = ['X','Y','Z','A', 'B:C', 'D']
#finding index of element 'Z'
z_index = l1.index('Z')
#slicing list from 0 until z_index
l2 = l1[:z_index]
print l2
Output:
['X', 'Y']
Generally, it is not a good idea to delete elements from a list you are iterating. In your case, you may consider creating a new list with the result you want:
l = ['X','Y','Z','A', 'B:C', 'D']
clean_l = [i for i in l if i not in ('A', 'B:C', 'D')]
Which is a good option if you know which elements you want to delete. However, if you know that you don't want anything after 'Z' regardless of their value, then just slice the list:
clean_l = l[:l.index('Z') + 1]
Firstly you would want to find the position of 'Z' by using the index() method.
x = ['X','Y','Z','A', 'B:C', 'D']
position = x.index('Z')
Then to delete everything after z i would do this:
del x[postion+1:]
You have to add one to the position otherwise it will delete 'Z' also

List index out of range error

So I am getting a list index out of range error in python again, and I can't figure out what's wrong.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
f1 = open("membrane_GO.txt","r")
new_list1 = f1.readlines()
new_list2 = new_list1
for i in range(len(new_list1)):
if "Reactome" in new_list1[i]:
new_list2.pop(i)
print new_list2
f1.close()
I made sure that the a duplicated list is being modified as the primary list is iterated over, so that can't be the problem.
Appreciate any help
Thanks :)
You only duplicated a reference to the list. If you want to make a separate copy of a list, use slices: list2 = list1[:] or look into the deepcopy module.
When you pop, the array size goes down. That means if the list has length 10, and you pop(0), then the list has length 9. If you then pop(9), which doesn't exist it will give you an out of bounds error.
Example:
>>> x = [0,1,2,3,4]
>>> print x, len(x)
[0,1,2,3,4], 5
>>> x.pop(0)
>>> print x, len(x)
[1,2,3,4], 4
This is an error in your case because you go from 0 to len(new_list1).
The approach I advise you to take is to create a new list where "Reactome" is not in new_list1[i].
You can do this easily in a list comprehension.
with open("membrane_GO.txt","r") as f:
lines = [line for line in f.readlines() if "Reactome" not in line]
print lines
Assume that your list is initially ['a', 'b', 'c'],
then list1 = list2 = ['a', 'b', 'c']
Then you perform iteration for len(list2), ie 3 times,
Then i will take values 0, 1, and 2.
In each iteration you are removing one element from list1.
i = 0
remove list1[0]
new list = ['b', 'c']
i = 1
remove list1[1]
new list = ['b']
i = 2
remove list[2] which does not exist.
So you will get a index out of bound error
Just to add to TigerHawks answer:
Because you have only duplicated the reference (not the list itself), when you pop() an element out of new_list2, you also remove it from new_list1 beceause they're both references to the same list.
Say there are 'n' elements in new_list1 at the start of the loop. It will run for 'n' iterations.
Suppose then that you pop an element out of new_list2 (and so out of new_list1 as well), within the loop, you will get an index out of range error when the loop tries to access the 'nth' element of a list which now only has 'n-1' elements in it
For this to work properly use slicing to copy the list:
new_list2 = new_list1[:]
Incidentally, for i in range(len(new_list1)): is considered un-pythonic, I believe. A 'better' way would be to use enumerate:
for index, element in enumerate(new_list1):
if "Reactome" in element:
new_list2.pop(index)

The condition skips 2 members of a list [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Modifying list while iterating
I have been given a task to make a code in python that will remove all members that occures more than once in a list and leave 1 copy of it.
Condition: it should be case-insesitive
So I've written down the following code:
string = raw_input()
list1 = string.split(",")
low_case_list = list1[:] #for case-insesitive
for i in range(len(low_case_list)):
low_case_list[i] = low_case_list[i].lower()
for member in low_case_list:
if(low_case_list.count(member) > 1):
del list1[low_case_list.index(member)]
del low_case_list[low_case_list.index(member)]
after the input I get this list: [a,b,c,d,A,B,C,D,a,b,c,d]
and after I do the operation on it: [B,D,a,b,c,d]
my question is, why it skips 'B' and 'D' when it removes the members?
Why not just convert your list into a set with all elements converted to lower-case, and then back to a list. You can use a generator for converting every element to lowercase.
You can do it like this: -
>>> l = ['a', 'b', 'c', 'A', 'B', 'C', 'a', 'b', 'c']
>>> new_list = list(set(elem.lower() for elem in l))
>>> new_list
['a', 'c', 'b']
Note that, order may be changed because, set does not maintain the order of it's elements.
You could try something like this instead:
input = raw_input().split(',')
unique = set([s.lower() for s in input])
result = list(unique)
Try this, should be simple.
Given your list li:
lowcase = [elem.lower() for elem in li]
output = []
for el in lowcase:
if el not in output: output.append(el)
return output # if necessary, otherwise a simple li = output
Or, in a faster and more elegant way, you could replace the whole for loop with:
[output.append(el) for el in lowcase if el not in output]
Your code should be buggy because you refer to the index of the element, but the list changes size during the loop, so indices change too.
EDIT: didn't think about sets, obviously they're the best solution here.

Categories