4

Is there a Pythonic way of returning the first item in a list which is also an item in another list? At the moment I'm doing it using brute force and ignorance:

def FindFirstMatch(a, b):
    """
    Returns the first element in a for which there is a matching
    element in b or None if there is no match
    """

    for item in a:
        if item in b:
            return item
    return None

So FindFirstMatch(['Fred','Wilma','Barney','Betty'], ['Dino', 'Pebbles', 'Wilma', 'Bambam']) returns 'Wilma' but I wondered if there was a more elegant/efficient/Pythonic way.

TimGJ
  • 1,584
  • 2
  • 16
  • 32
  • I'm not sure if Python sets might be the way to go here, but I need to match the FIRST item in list A with any item in list B, and I believe Python sets are unordered? – TimGJ Oct 16 '15 at 12:58
  • That seems fine, although you don't need `return None` explicitly. If the elements are hashable (like your strings), you could make `b` a set to be more efficient. – jonrsharpe Oct 16 '15 at 12:58
  • What is the technical term for >>> ? I could not find it in the docs. – ergonaut Oct 16 '15 at 13:00
  • @ergonaut it's the *"prompt"*; see https://docs.python.org/2/tutorial/interpreter.html#interactive-mode – jonrsharpe Oct 16 '15 at 13:01
  • @ergonaut https://docs.python.org/3/glossary.html – vaultah Oct 16 '15 at 13:02
  • 1
    `next(item for item in a if item in b)` – MrAlexBailey Oct 16 '15 at 13:03
  • @Jkdc In [125]: runfile('/home/tim/weightedvoting.py', wdir='/home/tim') File "/home/tim/weightedvoting.py", line 44 return next(for item in a if item in b) ^ SyntaxError: invalid syntax – TimGJ Oct 16 '15 at 13:06
  • 1
    @TimGJ you're missing the first `item`... – jonrsharpe Oct 16 '15 at 13:07
  • @jonrsharpe Doh! I noticed the instant I'd sent the comment. An old man in a hurry I'm afraid. – TimGJ Oct 16 '15 at 13:09
  • See this related question: [efficiently knowing if intersection of two list is empty or not](http://stackoverflow.com/questions/2197482/efficiently-knowing-if-intersection-of-two-list-is-empty-or-not-in-python). – Peter Wood Oct 16 '15 at 13:23

1 Answers1

6

You can use a generator expression and 'next()' function . Example -

def FindFirstMatch(list1, list2):
    """
    Returns the first element in list "list1" for which there is a matching
    element in list "list2" or None if there is no match
    """

    setb = set(list2)

    return next((item for item in list1 if item in setb),None)

This would also return None if no such item meeting the condition exist in 'list2' .

In the above function, I am first converting list 'list2' into a set , so that searching in it can be done in constant time (otherwise searching in list is an O(n) time complexity operation).

Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
  • Sweet. I would never have thought of using next. I suppose that's why stackoverflow is so useful. – TimGJ Oct 16 '15 at 13:13
  • I presume there is no particular advantage to converting it to a set before the `next` - i.e. it would be just as efficient to do it as `return next((item for item in a if item in set(b)), None)` – TimGJ Oct 16 '15 at 13:14
  • With your version it would convert the entire b list to set every time we check that condition , if you convert it to set before next , it would only be converted to set once . – Anand S Kumar Oct 16 '15 at 13:17
  • The code would be even more clearer, if you can use variable names like 'list1', 'list2', same for OP as well. – kmario23 Oct 16 '15 at 13:55