Get the first item from an iterable that matches a condition

前端 未结 13 2264
感情败类
感情败类 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 05:05

    The itertools module contains a filter function for iterators. The first element of the filtered iterator can be obtained by calling next() on it:

    from itertools import ifilter
    
    print ifilter((lambda i: i > 3), range(10)).next()
    
    0 讨论(0)
  • Oneliner:

    thefirst = [i for i in range(10) if i > 3][0]
    

    If youre not sure that any element will be valid according to the criteria, you should enclose this with try/except since that [0] can raise an IndexError.

    0 讨论(0)
  • 2020-11-22 05:06

    As a reusable, documented and tested function

    def first(iterable, condition = lambda x: True):
        """
        Returns the first item in the `iterable` that
        satisfies the `condition`.
    
        If the condition is not given, returns the first item of
        the iterable.
    
        Raises `StopIteration` if no item satysfing the condition is found.
    
        >>> first( (1,2,3), condition=lambda x: x % 2 == 0)
        2
        >>> first(range(3, 100))
        3
        >>> first( () )
        Traceback (most recent call last):
        ...
        StopIteration
        """
    
        return next(x for x in iterable if condition(x))
    

    Version with default argument

    @zorf suggested a version of this function where you can have a predefined return value if the iterable is empty or has no items matching the condition:

    def first(iterable, default = None, condition = lambda x: True):
        """
        Returns the first item in the `iterable` that
        satisfies the `condition`.
    
        If the condition is not given, returns the first item of
        the iterable.
    
        If the `default` argument is given and the iterable is empty,
        or if it has no items matching the condition, the `default` argument
        is returned if it matches the condition.
    
        The `default` argument being None is the same as it not being given.
    
        Raises `StopIteration` if no item satisfying the condition is found
        and default is not given or doesn't satisfy the condition.
    
        >>> first( (1,2,3), condition=lambda x: x % 2 == 0)
        2
        >>> first(range(3, 100))
        3
        >>> first( () )
        Traceback (most recent call last):
        ...
        StopIteration
        >>> first([], default=1)
        1
        >>> first([], default=1, condition=lambda x: x % 2 == 0)
        Traceback (most recent call last):
        ...
        StopIteration
        >>> first([1,3,5], default=1, condition=lambda x: x % 2 == 0)
        Traceback (most recent call last):
        ...
        StopIteration
        """
    
        try:
            return next(x for x in iterable if condition(x))
        except StopIteration:
            if default is not None and condition(default):
                return default
            else:
                raise
    
    0 讨论(0)
  • 2020-11-22 05:08

    For older versions of Python where the next built-in doesn't exist:

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

    Damn Exceptions!

    I love this answer. However, since next() raise a StopIteration exception when there are no items, i would use the following snippet to avoid an exception:

    a = []
    item = next((x for x in a), None)
    

    For example,

    a = []
    item = next(x for x in a)
    

    Will raise a StopIteration exception;

    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    
    0 讨论(0)
  • 2020-11-22 05:17

    You could also use the argwhere function in Numpy. For example:

    i) Find the first "l" in "helloworld":

    import numpy as np
    l = list("helloworld") # Create list
    i = np.argwhere(np.array(l)=="l") # i = array([[2],[3],[8]])
    index_of_first = i.min()
    

    ii) Find first random number > 0.1

    import numpy as np
    r = np.random.rand(50) # Create random numbers
    i = np.argwhere(r>0.1)
    index_of_first = i.min()
    

    iii) Find the last random number > 0.1

    import numpy as np
    r = np.random.rand(50) # Create random numbers
    i = np.argwhere(r>0.1)
    index_of_last = i.max()
    
    0 讨论(0)
提交回复
热议问题