Porz
Porz

Reputation: 183

How to return a matching item from a list in Python

I want my function to return one of the short string in the list if it exists in another piece of long string. How would you do it?

This is what comes up in my mind at the moment, but is there a better way to implement the func in Python?

>>> def func(shortStrList, longStr):
...     return shortStrList[[x in longStr for x in shortStrList].index(True)]
...
>>> func(['ABC', 'DEF', 'GHI'], 'PQRABCD')
'ABC'
>>> func(['ABC', 'DEF', 'GHI'], 'DEFPQRACD')
'DEF'

Upvotes: 3

Views: 5385

Answers (4)

Porz
Porz

Reputation: 183

To consolidate the answers/comments, and to do a quick test on the performance of different answers...

>>> def timeTest(s, f):
...     t1 = time.clock()
...     for x in xrange(s):
...         f(['ABC', 'DEF', 'GHI'], 'PQRABCD')
...         f(['ABC', 'DEF', 'GHI'], 'PQRACDEF')
...         f(['ABC', 'DEF', 'GHI'], 'PGHIQRCD')
...     t2 = time.clock()
...     print t2 - t1
...
>>>
>>> def func1(shortStrList, longStr):
...     return shortStrList[[x in longStr for x in shortStrList].index(True)]
... 
>>> timeTest(10000000, func1)
18.4710161502
>>>
>>> def func2(shortStrList, longStr):
...     return next(s for s in shortStrList if s in longStr)
... 
>>> timeTest(10000000, func2)
26.1494262581
>>>
>>> def func3(shortStrList, longStr):
...     filter( lambda x: x in longStr, shortStrList)[0]
...  
>>> timeTest(10000000, func3)
26.1221138429
>>>
>>> def func4(shortStrList, longStr):
...     for s in shortStrList:
...         if s in longStr: return s
...  
>>> timeTest(10000000, func4)
8.78067844999
>>>
>>> def func5(shortStrList, longStr):
...     return [string for string in shortStrList if string in longStr][0]
... 
>>> timeTest(10000000, func5)
12.549210555
>>>

Seems like doing the loop (func4) as Ekeyme Mo suggested is quickest. (though not sure if this can be re-written as one liner)

Just realised different methods maybe preferred if the length of the short string list differs. While the simple loop still performs the quickest, next() performs quicker than list comprehension when the list is long.

>>> def timeTest(s, f):
...     sl = ['ABC'] + ['ZXYZ']*50 + ['DEF'] + ['RQDSF']*50 + ['GHI']
...     t1 = time.clock()
...     for x in xrange(s):
...         f(sl, 'PQRABCD')
...         f(sl, 'PQRACDEF')
...         f(sl, 'PGHIQRCD')
...     t2 = time.clock()
...     print t2 - t1
...     
>>> def func1(shortStrList, longStr):
...     return shortStrList[[x in longStr for x in shortStrList].index(True)]
... 
>>> timeTest(100000, func1)
2.14106761862
>>> 
>>> def func2(shortStrList, longStr):
...     return next(s for s in shortStrList if s in longStr)
... 
>>> timeTest(100000, func2)
0.867831158122
>>> 
>>> def func3(shortStrList, longStr):
...     filter( lambda x: x in longStr, shortStrList)[0]
...     
>>> timeTest(100000, func3)
3.19491244615
>>> 
>>> def func4(shortStrList, longStr):
...     for s in shortStrList:
...         if s in longStr: return s
...         
>>> timeTest(100000, func4)
0.629572839949
>>> 
>>> def func5(shortStrList, longStr):
...     return [string for string in shortStrList if string in longStr][0]
... 
>>> timeTest(100000, func5)
1.31148152449
>>> 

Upvotes: 3

RoadRunner
RoadRunner

Reputation: 26315

You can just keep it simple like this:

def func(shortStrList, longStr):
    try:
        return [string for string in shortStrList if string in longStr][0]
    except IndexError:
        return("No matches found")

Output:

>>> func(['ABC', 'DEF', 'GHI'], 'PQRABCD')
'ABC'
>>> func(['ABC', 'DEF', 'GHI'], 'DEFPQRACD')
'DEF'
>>> func(['ABC', 'DEF', 'GHI'], 'ABCDEF')
'ABC'

You can also do it this way without list comprehensions. This stops as soon as it finds the first solution.

def func2(shortStrList, longStr):

    result = ""
    for string in shortStrList:
        if string in longStr:
            result += string
            break
    else:
        return("No matches found")

    return result

Or even this way, which is the most simplest approach:

def func3(shortStrList, longStr):
    result = []
    for string in shortStrList:
        if string in longStr:
            result.append(string)
    else:
        print("No matches found")

    return result[0]

Upvotes: 1

Harsh Trivedi
Harsh Trivedi

Reputation: 1624

For the matter of taste, you can use filter instead of list comprehensions if you like.

def func(shortStrList, longStr):
    filter( lambda x: x in longStr, shortStrList)[0]
func( ['ABC', 'DEF', 'GHI', 'JDSLDF'], 'PQRABCD')
# ABC

Hope it helps :)

Upvotes: 0

Aran-Fey
Aran-Fey

Reputation: 43166

You can use a generator expression with an if clause:

def func(shortStrList, longStr):
    return next(s for s in shortStrList if s in longStr)

Upvotes: 4

Related Questions