c00kiemonster
c00kiemonster

Reputation: 23381

Get first list index containing sub-string?

For lists, the method list.index(x) returns the index in the list of the first item whose value is x. But if I want to look inside the list items, and not just at the whole items, how do I make the most Pythoninc method for this?

For example, with

l = ['the cat ate the mouse',
     'the tiger ate the chicken',
     'the horse ate the straw']

this function would return 1 provided with the argument tiger.

Upvotes: 56

Views: 86756

Answers (11)

citynorman
citynorman

Reputation: 5292

I wanted to just get the text and not raise exception if item was not found

search = 'a'
next((s for s in ["aa",'c'] if search in s), None)

search = 'b'
next((el for el in ["aa",'c'] if search in el), None)

It's one of those things I wish was just implemented natively.

Upvotes: 1

peacefulzephyr
peacefulzephyr

Reputation: 1

@kennytm offers a great answer that helped me; to build from theirs a function that allows regex, I wrote:

def substringindex(inputlist, inputsubstring):
    s = [x for x in inputlist if re.search(inputsubstring, x)]

    if s != []:
        return (inputlist.index(s[0]), s[0])
    return -1

This function works exactly like theirs, but supports regex.

Upvotes: 0

Michael Gx Ou
Michael Gx Ou

Reputation: 1

Using map function:

index = np.nonzero(map(lambda x: substring in x, strings))[0][0]

Upvotes: 0

lev
lev

Reputation: 2997

With a one-liner:

index = [idx for idx, s in enumerate(l) if 'tiger' in s][0]

Upvotes: 40

Guido
Guido

Reputation: 76

imho with this line, you'll find only the first occurence without processing the whole list

index = next((i for i in enumerate(l) if "tiger" in i[1]),[-1,-1])[0]

Upvotes: 2

Pawel
Pawel

Reputation: 407

  >>> li = ['my','array','with','words']
  >>> reduce(lambda tup, word: (tup[0], True) if not tup[1] and word  == 'my' else (tup[0]+1 if not tup[1] else tup[0], tup[1]), li, (0, False))[0]
  0
  >>> reduce(lambda tup, word: (tup[0], True) if not tup[1] and word  == 'words' else (tup[0]+1 if not tup[1] else tup[0], tup[1]), li, (0, False))[0]
  3

Upvotes: 0

John La Rooy
John La Rooy

Reputation: 304493

Variation of abyx solution (optimised to stop when the match is found)

def first_substring(strings, substring):
    return next(i for i, string in enumerate(strings) if substring in string)

If you are pre 2.6 you'll need to put the next() at the end

def first_substring(strings, substring):
    return (i for i, string in enumerate(strings) if substring in string).next()

Upvotes: 9

abyx
abyx

Reputation: 73028

def first_substring(strings, substring):
    return min(i for i, string in enumerate(strings) if substring in string)

Note: This will raise ValueError in case no match is found, which is better in my opinion.

Upvotes: 2

kennytm
kennytm

Reputation: 523794

A non-slicky method:

def index_containing_substring(the_list, substring):
    for i, s in enumerate(the_list):
        if substring in s:
              return i
    return -1

Upvotes: 43

Max Shawabkeh
Max Shawabkeh

Reputation: 38683

This is quite slick and fairly efficient.

>>> def find(lst, predicate):
...     return (i for i, j in enumerate(lst) if predicate(j)).next()
... 
>>> l = ['the cat ate the mouse','the tiger ate the chicken','the horse ate the straw']
>>> find(l, lambda x: 'tiger' in x)
1

Only problem is that it will raise StopIteration if the item is not found (though that is easily remedied).

Upvotes: 3

Etienne Perot
Etienne Perot

Reputation: 4882

def find(l, s):
    for i in range(len(l)):
        if l[i].find(s)!=-1:
            return i
    return None # Or -1

Upvotes: 3

Related Questions