Completely remove one item from a list [duplicate] - python

This question already has answers here:
Elegant way to remove items from sequence in Python? [duplicate]
(14 answers)
Closed 8 years ago.
If I have a list like this:
MyList = [1,2,3,4,5,'hi', 6,7, 'hi', 8, 'hi', 9]
how can I remove all the items 'hi' from the list? I have tried the method remove() but it works only once:
MyList.remove('hi')
>>>> MyList
[1,2,3,4,5,6,7,'hi',8,'hi',9]
Yes, I could do something like this:
while 'hi' in MyList:
MyList.remove('hi')
but does anyone know any more elegant way than iterating n-times the same instruction?

while 'hi' in MyList: MyList.remove('hi') is O(N**2), better use a simple list comprehension which does the same thing in O(N) time:
MyList = [item for item in MyList if item != 'hi']

Use a list comprehension:
MyList = [v for v in MyList if v != 'hi']
This rebuilds the list to only contain values not equal to 'hi'.
list.remove() calls must move the rest of the list items forward, using a list comprehension instead is more efficient.

You can use filter function I guess.
Here is docs: filter docs
MyList = [1,2,3,4,5,'hi', 6,7, 'hi', 8, 'hi', 9]
def f(item, element="hi"):
if item == element:
return False
else:
return True
print filter(f, MyList)
>>> [1, 2, 3, 4, 5, 6, 7, 8, 9]
Thanks to Tim Pietzcker for his improvement.
The f function could be shorter
def f(item, element="hi"): return item != element

You can also use generator expression:
NewList = (x for x in MyList if x != 'hi')
Then you can iterate this as NewList.next() until it raise StopIteration.

Related

List index out of range in loop [duplicate]

This question already has answers here:
python : list index out of range error while iteratively popping elements
(12 answers)
Closed 2 years ago.
Im getting an error for list index being out of range. Sorry if this is a stupid question.
def filter_list(l):
for x in range(0, len(l)):
if type(l[x]) is str:
del l[x]
return l
When you use del to delete the item in the list, the list actually shortens and it seems like that is what is causing the problem.
If you would like to filter lists, you could use list comprehensions like so:
def filter(l):
return [item for item in l if type(item) is not str]
Usually, when looping over lists, it is good practice not to delete or insert new items.
Hope this helped
You should not definitely change a list while iterating over it. It is very bad practise... it can lead to a whole lot of errors for you. Either you should create a copy of use something else, as list comprehension:
def filter_list(l):
return [x for x in l if type(x) is not str]
print(filter_list([1, 4, 5, 's', 'demo'])) # Prints [1, 4, 5]

How do you know if something is in an array or not in python?

If I have something like:
list = [[1,2,3],[4,5,6],[7,8,9]]
Then how do I check if 1 is in the first, second, or third array?
I want it to be able to make an expression such as:
if 1 is in list 1:
do something
elif i is in list 2:
do something
else:
do something
Try using any:
any(1 in sub for sub in [[1,2,3],[4,5,6],[7,8,9]])
>>> list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> any(1 in sub for sub in list)
True
>>> any(10 in sub for sub in list)
False
>>> any(7 in sub for sub in list)
True
>>>
Well, if you know the contents of the list, you can use
if 1 in list[0]:
do_something()
elif 1 in list[1]:
do_something_else()
else: # 1 is in list[2]
do_something_different()
Derived from "Dive Into Python"
list = [[1,2,3],[4,5,6],[7,8,9]]
if 1 in list[0]:
do something
elif 1 in list[1]:
do something
else:
do something
...and so on. The in keyword takes a preceding value argument and returns a true if that value is in the proceeding list, false otherwise. The only other thing to know is list[0] accesses your first element in the top level list (the first sublist) and so on, allowing it to be searched for a specific integer using the in keyword.
Here's the expected output:
>>> list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> 1 in list[0]
True
>>> 1 in list[1]
False
To search all lists you can use the for keyword to loop over your lists and any to return true if any of the sublists match.
>>> any(1 in sublist for sublist in list)
True
>>> any(42 in sublist for sublist in list)
False
You can use Python's built-in "in" operator. This operator returns True if the item is in the iterable (list in this case), or False if it is not.
x_in_array = x in array
The Python doc that covers this is here, under section 5.6:
https://docs.python.org/2/library/stdtypes.html
Your if/elif/else statements would then look like:
if x in array_1:
# do something
elif x in array_2:
# do something
else:
# do something else
If you want to return the index of the list:
>>> def idx_check(i, l):
... for (idx, val) in enumerate(l):
... if i in val:
... return idx
... return None
...
>>> l = [[1,2,3],[4,5,6],[7,8,9]]
>>> idx_check(1, l)
0
>>> idx_check(4, l)
1
>>> idx_check(7, l)
2
First of all: I know it's just an example, but don't use list as a variable in Python. It is a keyword/built-in function.
Second: you can use iteration to accomplish this. You can iterate through the members of a list (or any iterable object, or any iterator) like this:
for item in L:
# do something with item
You can keep track of the number of times you have entered the loop using the enumerate function. The enumerate function returns a two-tuple in the form of member_index_number, member:
for num,item in enumerate(L):
# do something with num and item
Almost there- now you need a way to associate the above iteration with your list of functions. The usual way this is done in python is with a dictionary, but you could also just use a list.
# list way
funcs_list = [f1, f2, f3]
for num,item in enumerate(L):
if 1 in item:
funcs_list[funcs_list.index(num)]()
break
# dictionary way
funcs_dict = {0: f1, 1: f2, 2: f3}
for num,item in enumerate(L):
if 1 in item:
funcs_dict[num]()
break
The dictionary method is usually preferred because it looks much cleaner.

Python - list comprehension , 2D list

I'm trying to figure out how to delete duplicates from 2D list. Let's say for example:
x= [[1,2], [3,2]]
I want the result:
[1, 2, 3]
in this order.
Actually I don't understand why my code doesn't do that :
def removeDuplicates(listNumbers):
finalList=[]
finalList=[number for numbers in listNumbers for number in numbers if number not in finalList]
return finalList
If I should write it in nested for-loop form it'd look same
def removeDuplicates(listNumbers):
finalList=[]
for numbers in listNumbers:
for number in numbers:
if number not in finalList:
finalList.append(number)
return finalList
"Problem" is that this code runs perfectly. Second problem is that order is important. Thanks
finalList is always an empty list on your list-comprehension even though you think it's appending during that to it, which is not the same exact case as the second code (double for loop).
What I would do instead, is use set:
>>> set(i for sub_l in x for i in sub_l)
{1, 2, 3}
EDIT:
Otherway, if order matters and approaching your try:
>>> final_list = []
>>> x_flat = [i for sub_l in x for i in sub_l]
>>> list(filter(lambda x: f.append(x) if x not in final_list else None, x_flat))
[] #useless list thrown away and consumesn memory
>>> f
[1, 2, 3]
Or
>>> list(map(lambda x: final_list.append(x) if x not in final_list else None, x_flat))
[None, None, None, None] #useless list thrown away and consumesn memory
>>> f
[1, 2, 3]
EDIT2:
As mentioned by timgeb, obviously the map & filter will throw away lists that are at the end useless and worse than that, they consume memory. So, I would go with the nested for loop as you did in your last code example, but if you want it with the list comprehension approach than:
>>> x_flat = [i for sub_l in x for i in sub_l]
>>> final_list = []
>>> for number in x_flat:
if number not in final_list:
finalList.append(number)
The expression on the right-hand-side is evalueated first, before assigning the result of this list comprehension to the finalList.
Whereas in your second approach you write to this list all the time between the iterations. That's the difference.
That may be similar to the considerations why the manuals warn about unexpected behaviour when writing to the iterated iterable inside a for loop.
you could use the built-in set()-method to remove duplicates (you have to do flatten() on your list before)
You declare finalList as the empty list first, so
if number not in finalList
will be False all the time.
The right hand side of your comprehension will be evaluated before the assignment takes place.
Iterate over the iterator chain.from_iterable gives you and remove duplicates in the usual way:
>>> from itertools import chain
>>> x=[[1,2],[3,2]]
>>>
>>> seen = set()
>>> result = []
>>> for item in chain.from_iterable(x):
... if item not in seen:
... result.append(item)
... seen.add(item)
...
>>> result
[1, 2, 3]
Further reading: How do you remove duplicates from a list in Python whilst preserving order?
edit:
You don't need the import to flatten the list, you could just use the generator
(item for sublist in x for item in sublist)
instead of chain.from_iterable(x).
There is no way in Python to refer to the current comprehesion. In fact, if you remove the line finalList=[], which does nothing, you would get an error.
You can do it in two steps:
finalList = [number for numbers in listNumbers for number in numbers]
finalList = list(set(finalList))
or if you want a one-liner:
finalList = list(set(number for numbers in listNumbers for number in numbers))

Python removing items from list [duplicate]

This question already has answers here:
Strange result when removing item from a list while iterating over it
(8 answers)
Closed 7 years ago.
I have a list in the given format:
[['John', 'Smith'], ['Linus', 'Torvalds'], ['Bart', 'Simpson']]
There are some elements like this in the list ['Linus Torvalds', ''] and I want to remove those. So why doesn't the following code remove them?
for i in people:
if(i[0] == '' or i[1] == ''):
print people.pop(people.index(i))
You are changing the list while iterating over it and this is the source of your problems. An approach that works is
people[:] = [p for p in people if p[0] != '' and p[1] != '']
this way a new temporary list containing only the elements you want is built and then assigned to the original list object when the operation is complete.
Or even people[:] = [p for p in people if all(p)] if you want to resize the list "in place".
You're modifying the list's length while iterating over it. That causes you to skip values. When you pop one item off the list, here's what happens (stealing from this answer):
[1, 2, 3, 4, 5, 6...]
^
That's the state of the list initially; now say 1 is removed and the loop goes to the second item in the list:
[2, 3, 4, 5, 6...]
^
And so on.
It's a bad idea to remove things from a list as you iterate over it. So, try one of these instead (Also, I think your condition is not what you want it to be - I've fixed it):
L = [['John', 'Smith'], ['Linus', 'Torvalds'], ['Bart', 'Simpson']]
delete_these = []
for index, i in enumerate(L):
if not i[-1].strip():
delete_these.append(i)
for i in delete_these:
L.pop(i)
delete_these = map(lambda x: x-1, delete_these)
OR
L = [i for i in L if i[-1].strip()]
OR
answer = []
for i in L:
if i[-1].strip():
answer.append(i)
OR
i = 0
while i < len(L):
if not L[i][-1].strip():
L.pop(i)
else:
i += 1
Hope this helps

Python: finding an element in a list [duplicate]

This question already has answers here:
Finding the index of an item in a list
(43 answers)
Closed 9 years ago.
What is a good way to find the index of an element in a list in Python?
Note that the list may not be sorted.
Is there a way to specify what comparison operator to use?
From Dive Into Python:
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> li.index("example")
5
If you just want to find out if an element is contained in the list or not:
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> 'example' in li
True
>>> 'damn' in li
False
The best way is probably to use the list method .index.
For the objects in the list, you can do something like:
def __eq__(self, other):
return self.Value == other.Value
with any special processing you need.
You can also use a for/in statement with enumerate(arr)
Example of finding the index of an item that has value > 100.
for index, item in enumerate(arr):
if item > 100:
return index, item
Source
Here is another way using list comprehension (some people might find it debatable). It is very approachable for simple tests, e.g. comparisons on object attributes (which I need a lot):
el = [x for x in mylist if x.attr == "foo"][0]
Of course this assumes the existence (and, actually, uniqueness) of a suitable element in the list.
assuming you want to find a value in a numpy array,
I guess something like this might work:
Numpy.where(arr=="value")[0]
There is the index method, i = array.index(value), but I don't think you can specify a custom comparison operator. It wouldn't be hard to write your own function to do so, though:
def custom_index(array, compare_function):
for i, v in enumerate(array):
if compare_function(v):
return i
I use function for returning index for the matching element (Python 2.6):
def index(l, f):
return next((i for i in xrange(len(l)) if f(l[i])), None)
Then use it via lambda function for retrieving needed element by any required equation e.g. by using element name.
element = mylist[index(mylist, lambda item: item["name"] == "my name")]
If i need to use it in several places in my code i just define specific find function e.g. for finding element by name:
def find_name(l, name):
return l[index(l, lambda item: item["name"] == name)]
And then it is quite easy and readable:
element = find_name(mylist,"my name")
The index method of a list will do this for you. If you want to guarantee order, sort the list first using sorted(). Sorted accepts a cmp or key parameter to dictate how the sorting will happen:
a = [5, 4, 3]
print sorted(a).index(5)
Or:
a = ['one', 'aardvark', 'a']
print sorted(a, key=len).index('a')
how's this one?
def global_index(lst, test):
return ( pair[0] for pair in zip(range(len(lst)), lst) if test(pair[1]) )
Usage:
>>> global_index([1, 2, 3, 4, 5, 6], lambda x: x>3)
<generator object <genexpr> at ...>
>>> list(_)
[3, 4, 5]
I found this by adapting some tutos. Thanks to google, and to all of you ;)
def findall(L, test):
i=0
indices = []
while(True):
try:
# next value in list passing the test
nextvalue = filter(test, L[i:])[0]
# add index of this value in the index list,
# by searching the value in L[i:]
indices.append(L.index(nextvalue, i))
# iterate i, that is the next index from where to search
i=indices[-1]+1
#when there is no further "good value", filter returns [],
# hence there is an out of range exeption
except IndexError:
return indices
A very simple use:
a = [0,0,2,1]
ind = findall(a, lambda x:x>0))
[2, 3]
P.S. scuse my english

Categories

Resources