Get the first item from an iterable that matches a condition

前端 未结 13 2287
感情败类
感情败类 2020-11-22 04:43

I would like to get the first item from a list matching a condition. It\'s important that the resulting method not process the entire list, which could be quite large. For e

相关标签:
13条回答
  • 2020-11-22 04:54

    Similar to using ifilter, you could use a generator expression:

    >>> (x for x in xrange(10) if x > 5).next()
    6
    

    In either case, you probably want to catch StopIteration though, in case no elements satisfy your condition.

    Technically speaking, I suppose you could do something like this:

    >>> foo = None
    >>> for foo in (x for x in xrange(10) if x > 5): break
    ... 
    >>> foo
    6
    

    It would avoid having to make a try/except block. But that seems kind of obscure and abusive to the syntax.

    0 讨论(0)
  • 2020-11-22 04:55

    By using

    (index for index, value in enumerate(the_iterable) if condition(value))
    

    one can check the condition of the value of the first item in the_iterable, and obtain its index without the need to evaluate all of the items in the_iterable.

    The complete expression to use is

    first_index = next(index for index, value in enumerate(the_iterable) if condition(value))
    

    Here first_index assumes the value of the first value identified in the expression discussed above.

    0 讨论(0)
  • 2020-11-22 04:56

    The most efficient way in Python 3 are one of the following (using a similar example):

    With "comprehension" style:

    next(i for i in range(100000000) if i == 1000)
    

    WARNING: The expression works also with Python 2, but in the example is used range that returns an iterable object in Python 3 instead of a list like Python 2 (if you want to construct an iterable in Python 2 use xrange instead).

    Note that the expression avoid to construct a list in the comprehension expression next([i for ...]), that would cause to create a list with all the elements before filter the elements, and would cause to process the entire options, instead of stop the iteration once i == 1000.

    With "functional" style:

    next(filter(lambda i: i == 1000, range(100000000)))
    

    WARNING: This doesn't work in Python 2, even replacing range with xrange due that filter create a list instead of a iterator (inefficient), and the next function only works with iterators.

    Default value

    As mentioned in other responses, you must add a extra-parameter to the function next if you want to avoid an exception raised when the condition is not fulfilled.

    "functional" style:

    next(filter(lambda i: i == 1000, range(100000000)), False)
    

    "comprehension" style:

    With this style you need to surround the comprehension expression with () to avoid a SyntaxError: Generator expression must be parenthesized if not sole argument:

    next((i for i in range(100000000) if i == 1000), False)
    
    0 讨论(0)
  • 2020-11-22 05:00

    In Python 3:

    a = (None, False, 0, 1)
    assert next(filter(None, a)) == 1
    

    In Python 2.6:

    a = (None, False, 0, 1)
    assert next(iter(filter(None, a))) == 1
    

    EDIT: I thought it was obvious, but apparently not: instead of None you can pass a function (or a lambda) with a check for the condition:

    a = [2,3,4,5,6,7,8]
    assert next(filter(lambda x: x%2, a)) == 3
    
    0 讨论(0)
  • 2020-11-22 05:01

    I would write this

    next(x for x in xrange(10) if x > 3)
    
    0 讨论(0)
  • 2020-11-22 05:03

    This question already has great answers. I'm only adding my two cents because I landed here trying to find a solution to my own problem, which is very similar to the OP.

    If you want to find the INDEX of the first item matching a criteria using generators, you can simply do:

    next(index for index, value in enumerate(iterable) if condition)
    
    0 讨论(0)
提交回复
热议问题