В Python, как я могу найти индекс первого элемента в списке, который НЕ является некоторым значением?
Тип списка Python имеет метод index (x). Он принимает один параметр x и возвращает индекс (целочисленный) первого элемента в списке, который имеет значение x.
В принципе, мне нужно инвертировать метод index (x). Мне нужно получить индекс первого значения в списке, который НЕ имеет значения x. Я бы, вероятно, мог бы просто использовать функцию, которая возвращает индекс первого элемента со значением!= Нет.
Я могу думать о реализации цикла for for с переменной переменной счетчика, но я чувствую, что что-то не хватает. Есть ли существующий метод или однострочная конструкция Python, которая может справиться с этим?
В моей программе ситуация возникает, когда я обрабатываю списки, возвращаемые из сложных регулярных совпадений. Все, кроме одного элемента в каждом списке, имеют значение None. Если мне просто нужна строка с совпадением, я мог бы использовать представление списка, например "[x для x в [my_list], если x не является None]", но мне нужен индекс, чтобы выяснить, какая группа захвата в моем регулярном выражении фактически вызвала матч.
Ответы
Ответ 1
Выход из первого совпадения очень просто: вместо вычисления полного понимания списка (затем отбрасывая все, кроме первого элемента), используйте next
над геном xp. Предположим, например, что вы хотите -1
, когда ни один элемент не удовлетворяет условию != x
,
return next((i for i, v in enumerate(L) if v != x), -1)
Это синтаксис Python 2.6; если вы застряли с 2.5 или более ранними версиями, .next()
- это метод genexp (или другого итератора) и не принимает значение по умолчанию, например, как -1
(так что если вы не хотите видеть StopIteration
исключение вам придется использовать try
/except
). Но тогда есть причина, по которой после 2.5 были выпущены релизы - непрерывное совершенствование языка и его встроенных модулей! -)
Ответ 2
Использование понимания списка, когда вам нужен только первый, просто чувствует слизь (мне). Используйте for-loop и выйдите раньше.
>>> lst = [None, None, None, "foo", None]
>>> for i, item in enumerate(lst):
... if item: break
... else:
... print "not found"
...
>>> i
3
Ответ 3
enumerate()
возвращает итератор, который дает кортеж текущего индекса итеративного, а также самого элемента.
Ответ 4
[i for i, x in enumerate(my_list) if x != value][0]
Если вы не уверены, есть ли несоответствующий элемент, используйте это вместо:
match = [i for i, x in enumerate(my_list) if x != value]
if match:
i = match[0]
# i is your number.
Вы можете сделать это еще более "функциональным" с помощью itertools, но вы скоро достигнете точки, в которой проще для цикла. Даже вышеприведенные решения не так эффективны, как цикл for, поскольку они строят список всех несоответствующих индексов, прежде чем тянуть интерес.
Ответ 5
Глупое решение на основе itertools:)
import itertools as it, operator as op, functools as ft
def index_ne(item, sequence):
sequence= iter(sequence)
counter= it.count(-1) # start counting at -1
pairs= it.izip(sequence, counter) # pair them
get_1st= it.imap(op.itemgetter(0), pairs) # drop the used counter value
ne_scanner= it.ifilter(ft.partial(op.ne, item), get_1st) # get only not-equals
try:
ne_scanner.next() # this should be the first not equal
except StopIteration:
return None # or raise some exception, all items equal to item
else:
return counter.next() # should be the index of the not-equal item
if __name__ == "__main__":
import random
test_data= [0]*20
print "failure", index_ne(0, test_data)
index= random.randrange(len(test_data))
test_data[index]= 1
print "success:", index_ne(0, test_data), "should be", index
Все это просто для того, чтобы воспользоваться подсчетом itertools.count
:)