Python: Find in list
I have come across this:
item = someSortOfSelection() if item in myList: doMySpecialFunction(item)
but sometimes it does not work with all my items, as if they weren't recognized in the list (when it's a list of string).
Is this the most 'pythonic' way of finding an item in a list:
if x in l:?
As for your first question: that code is perfectly fine and should work if
item equals one of the elements inside
myList. Maybe you try to find a string that does not exactly match one of the items or maybe you are using a float value which suffers from inaccuracy.
As for your second question: There's actually several possible ways if "finding" things in lists.
Checking if something is inside
This is the use case you describe: Checking whether something is inside a list or not. As you know, you can use the
in operator for that:
3 in [1, 2, 3] # => True
Filtering a collection
That is, finding all elements in a sequence that meet a certain condition. You can use list comprehension or generator expressions for that:
matches = [x for x in lst if fulfills_some_condition(x)] matches = (x for x in lst if x > 6)
The latter will return a generator which you can imagine as a sort of lazy list that will only be built as soon as you iterate through it. By the way, the first one is exactly equivalent to
matches = filter(fulfills_some_condition, lst)
in Python 2. Here you can see higher-order functions at work. In Python 3,
filter doesn't return a list, but a generator-like object.
Finding the first occurrence
If you only want the first thing that matches a condition (but you don't know what it is yet), it's fine to use a for loop (possibly using the
else clause as well, which is not really well-known). You can also use
next(x for x in lst if ...)
which will return the first match or raise a
StopIteration if none is found. Alternatively, you can use
next((x for x in lst if ...), [default value])
Finding the location of an item
For lists, there's also the
index method that can sometimes be useful if you want to know where a certain element is in the list:
[1,2,3].index(2) # => 1 [1,2,3].index(4) # => ValueError
However, note that if you have duplicates,
.index always returns the lowest index:......
[1,2,3,2].index(2) # => 1
If there are duplicates and you want all the indexes then you can use
[i for i,x in enumerate([1,2,3,2]) if x==2] # => [1, 3]
Read more... Read less...
If you want to find one element or
None use default in
next, it won't raise
StopIteration if the item was not found in the list:
first_or_default = next((x for x in lst if ...), None)
While the answer from Niklas B. is pretty comprehensive, when we want to find an item in a list it is sometimes useful to get its index:
next((i for i, x in enumerate(lst) if [condition on x]), [default value])
Finding the first occurrence
There's a recipe for that in
def first_true(iterable, default=False, pred=None): """Returns the first true value in the iterable. If no true value is found, returns *default* If *pred* is not None, returns the first item for which pred(item) is true. """ # first_true([a,b,c], x) --> a or b or c or x # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x return next(filter(pred, iterable), default)
For example, the following code finds the first odd number in a list:
>>> first_true([2,3,4,5], None, lambda x: x%2==1) 3
Another alternative: you can check if an item is in a list with
if item in list:, but this is order O(n). If you are dealing with big lists of items and all you need to know is whether something is a member of your list, you can convert the list to a set first and take advantage of constant time set lookup:
my_set = set(my_list) if item in my_set: # much faster on average than using a list # do something
Not going to be the correct solution in every case, but for some cases this might give you better performance.
Note that creating the set with
set(my_list) is also O(n), so if you only need to do this once then it isn't any faster to do it this way. If you need to repeatedly check membership though, then this will be O(1) for every lookup after that initial set creation.
You may want to use one of two possible searches while working with list of strings:
if list element is equal to an item ('example' is in ['one','example','two']):
if item in your_list: some_function_on_true()
'ex' in ['one','ex','two'] => True
'ex_1' in ['one','ex','two'] => False
if list element is like an item ('ex' is in ['one,'example','two'] or 'example_1' is in ['one','example','two']):
matches = [el for el in your_list if item in el]
matches = [el for el in your_list if el in item]
then just check
len(matches)or read them if needed.