пятница, 17 апреля 2009 г.

Поиск значения в списке

Итак в продолжение темы рецептов - ищем элемент в списке, как это не странно Python 2.5 этого делать нормально не умеет.
Раньше я делал это примерно так

a = None
for x in list:
if pred(x):
a = x

Очевидно что это не удобно. Как это обойти я подсмотрел здесь (там описано гораздо больше вариантов, но все они плохо работают с случаем когда ничего не найдено)

Итак делаем функцию find (которая должна бы быть в стандартной библиотеке языка)

def find(f, seq):
"""Return first item in sequence where f(item) == True."""
for item in seq:
if f(item):
return item

Дальше поиск прост

a = find(lambda x: x.id == 5, values) #will find value with id == 5 or None if nothing found

Стоит отметить что в 2.6 версии эта проблема решена и все гораздо проще (спасибо @ mishok13 за пример)

next((x for x in seq if pred(x)), None)
или для нашего примера
next((x for x in values if x.id == 5), None)

Какие есть еще более изящные варианты?

5 комментариев:

Traut комментирует...

как вариант:

>>> some = [1,2,3,4,5]
>>> func = lambda x: x == 3
>>> filter(func, some)
[3]
>>> func2 = lambda x: x == 100
>>> filter(func2, some)
[]

Unknown комментирует...

>>> some = [1,2,3,4,5]
>>> [ x for x in some if x==3]

Andrii V. Mishkovskyi комментирует...

Комментаторы упустили основною мысль -- нужен или первый найденный обьект (один) или некий другой обьект.
Вот рецепт:
>>> seq = range(10)
>>> ([x for x in seq if x == 3] or [42])[0]
3
>>> ([x for x in seq if x == 13] or [42])[0]
42
Для любителей filter, тоже самое:
>>> (filter(lambda x: x == 3, seq) or [42])[0]
3
>>> (filter(lambda x: x == 13, seq) or [42])[0]
42
Но всё таки, лучше использовать builtin next, как я и советовал. Имплементация на питоне элементарна.

Unknown комментирует...

вопрос значит правильно ставить надо. list comprehension IMHO самый что ни на есть питоновский way to go. остальное - детали.

Max Ischenko комментирует...

угу, у меня тоже такая функция написана.