2010-03-03 2 views
6

Мне нужна функция, которая способна выполнять итерацию по коллекции, вызывая предоставленную функцию с элементом коллекции в качестве параметра и возвращая параметр или индекс при получении «True» из предоставленной функции.Python - функциональный "find"?

Он somethong так:

def find(f, seq, index_only=True, item_only=False): 
    """Return first item in sequence where f(item) == True.""" 
    index = 0 
    for item in seq: 
     if f(item): 
      if index_only: 
       return index 
      if item_only: 
       return item 
      return index, item 
     index+= 1 
    raise KeyError 

Так мне интересно, есть ли что-нибудь подобное в стандартном наборе инструментов питона?

+2

Фрагмент OP - это более прямой (хотя и более длинный) способ выражения требования; это может быть предписанным образом, в зависимости от ситуации. Из ответов, однако, приходит очень полезная информация: «в отношении циклов, когда есть сомнения, проконсультируйтесь/рассмотрите itertools». – mjv

ответ

2

Вы можете использовать itertools.dropwhile, чтобы пропустить пункты, для которых возвращается функция False, а затем взять первый элемент остального (если есть). Если вам нужен индекс, а не элемент, включите enumerate из раздела «Рецепты» itertools docs.

Чтобы изменить значения истинности, возвращенные в комплект поставки функции, использовать lambda (lambda x: not pred (x), где pred является входящий в комплект поставки функции) или именованный обертку:

def negate(f): 
    def wrapped(x): 
     return not f(x) 
    return wrapped 

Пример:

def odd(x): return x % 2 == 1 
itertools.dropwhile(negate(odd), [2,4,1]).next() 
# => 1 

Это будет throw StopIteration, если соответствующий элемент не найден; оберните его в свою собственную функцию, чтобы вместо этого выбрать исключение из вашего выбора.

+0

:(Я думаю, что вопрос OP сам по себе является ответом, это может быть немного больше для простой итерации. –

+0

Я согласен с Anurag, но если использовать 'itertools', я думаю, что' ifilter' будет проще. Ex: 'itertools.ifilter (нечетный, [2,4,1]). next() ' – tgray

+0

Я склонен согласиться с' ifilter'. Кроме того, фрагмент OP действительно решает основную проблему просто отлично, но, интересно, что там в стандартный lib, чтобы избежать написания кода для таких вещей, кажется довольно разумным. Я бы сказал, что комментарий mjv по этому вопросу представляет собой важный урок здесь. –

3

Я не думаю, что есть такая функция с такой точной семантикой, и в любом случае ваша функция коротка, достаточно хороша, и вы можете легко ее улучшить для последующего использования, поэтому используйте ее.

потому что простой лучше, чем сложный.

Смежные вопросы