2012-03-26 3 views
205

Что было бы самым элегантным и эффективным способом поиска/возврата первого элемента списка, соответствующего определенному критерию?найти элемент первой последовательности, соответствующий критерию

Например, если у меня есть список объектов, и я хотел бы получить первый объект с атрибутом obj.val==5. Я мог бы, конечно, использовать понимание списка, но это повлекло бы за собой O (n), и если n велико, это расточительно. Я мог бы также использовать цикл с break, как только критерий был удовлетворен, но я подумал, что может быть больше pythonic/элегантное решение.

+2

что, если вы хотите получить деталь и индекс? –

+1

@CharlieParker, чтобы получить как индекс, так и элемент, используйте enumerate() - next ((idx, obj) для idx, obj в enumerate (objs), если obj.val == 5) –

ответ

367

Если у вас нет каких-либо других индексов или отсортированной информации для ваших объектов, то вам придется перебирать до такого объект не найден:

next(obj for obj in objs if obj.val==5) 

Это, однако быстрее, чем полный список понимание. Сравните эти два:

[i for i in xrange(100000) if i == 1000][0] 

next(i for i in xrange(100000) if i == 1000) 

Первый из них нуждается в 5.75ms, второй 58.3μs (в 100 раз быстрее, поскольку цикл в 100 раз короче).

+93

'next' также предоставляет' default', если объект не существует. Например. 'next ((i для i в диапазоне (500), если i> 600), 600)' вернет 600. – Darthfett

+22

Python [** 'next()' **] (http://docs.python.org/2 /library/functions.html#next) –

+5

Ну, это он, но я просто ожидал, что правильный ответ будет выглядеть круче. Мы всегда рекламируем python за то, что так элегантно. Если вы хотите, чтобы он был надежным, вы должны указать 'default' (например,' None') - и тогда вам не нужно забывать, что выражение генератора должно быть заключено в скобки, если не единственным аргументом ... Ну, как это влияет на читаемость ? Например. первая непустая пресс-форма: 'next ((arg для arg в sys.argv, если не os.path.exists (arg)), None)' - не очень дружелюбно. –

2
a=[100,200,300,400,500] 
def search(b): 
try: 
    k=a.index(b) 
    return a[k] 
except ValueError: 
    return 'not found' 
print(search(500)) 

он будет возвращать объект, если найден еще он будет возвращать «не найден»

+0

Это хорошо, но работает только тогда, когда критерии являются сопоставлением с элементом списка. Я искал более общее решение для обработки более широкого диапазона выбора – Jonathan

+0

, но @Jonathan в вашем вопросе, который вы упомянули **, эффективный способ нахождения \ возврата первого элемента списка **, поэтому приведенный выше список a = [100,200,300,400,500] может содержать любые тип объекта не только числа. –

+1

, и я заканчиваю предложение «..., которое соответствует определенным критериям», что не совпадает с совпадением на равенстве или идентичности :) Я сделал +1, поскольку я думаю, что ваше решение подходит для равенства \ identity private case – Jonathan

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