I have a list of long strings and I'd like to get the indexes of the list elements that match a substring of strings in another list. Checking if a list item contains a a single string inside a list is easy to do with list comprehensions, like this question:
my_list = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
thing_to_find = "abc"
matching = [i for i, x in enumerate(my_list) if thing_to_find in x]
However, I'd like to check not only if "abc"
is in x
, but if any strings in another list are in the list, like so:
my_list = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
things_to_find = ['abc', 'def']
This obviously doesn't work (but it would be really cool if it did):
matching = [i for i, x in enumerate(my_list) if things_to_find in x]
I can find the list indexes if I run commands individually, but it's tedious and horrible:
print([i for i, x in enumerate(my_list) if 'abc' in x])
# [0, 3]
print([i for i, x in enumerate(my_list) if 'def' in x])
# [1]
What's the best way to find the indexes of all instances where elements from one list are found in another list?
You are looking for the any()
function here:
matching = [i for i, x in enumerate(my_list) if any(thing in x for thing in things_to_find)]
Demo:
>>> my_list = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
>>> things_to_find = ['abc', 'def']
>>> [i for i, x in enumerate(my_list) if any(thing in x for thing in things_to_find)]
[0, 1, 3]
Maybe something like?:
my_list = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
things_to_find = ['abc', 'def']
for n, e in enumerate(my_list):
for m in things_to_find:
if m in e:
print '%s is in %s at %s' % (m, e, n)
Output:
abc is in abc-123 at 0
def is in def-456 at 1
abc is in abc-456 at 3
You are close:
matching = [i for i, x in enumerate(my_list) for keyword in things_to_find if keyword in x]
which gives [0,1,3]
.
You need to iterate through the things_to_find
list as well, and see if the keyword
is in x
.
Might be a little slow, but why not try:
my_list = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
things_to_find = ['abc', 'def']
for thing_to_find in things_to_find:
matching = [i for i, x in enumerate(my_list) if thing_to_find in x]
Build a regex, then test each list element against that:
import re
#must use search, not match because no wildcards, unless only looking for prefixes
regex = re.compile('|'.join(re.escape(interest) for interest in things_to_find))
Don't rebuild the regex every time you do the search - only rebuild when things_to_find
changes.
I suspect you don't want the indices, but the elements:
[x for x in my_list if regex.search(x)]
Or, if you really do want the indices:
[i for i,x in enumerate(my_list) if regex.search(x)]
This will likely perform better than an any(in)
solution (which is quadratic) for large things_to_find
lists, but will be overkill for short lists. You'll also see more of a gain where the things in things_to_find
are similar; and less of a gain if you can sort things_to_find
such that more likely matches occur first, and if matches are likely.
my_list = ['abc-123', 'def-456', 'ghi-789', 'abc-456']
things_to_find = ['abc', 'def']
matching = [[i for i, x in enumerate(my_list) if y in x]for y in things_to_find]