Лучший способ обработки list.index(возможно, не существует) в python?
У меня есть код, который выглядит примерно так:
thing_index = thing_list.index(thing)
otherfunction(thing_list, thing_index)
ok, чтобы упростить, но вы поняли эту идею. Теперь thing
не может быть действительно в списке, и в этом случае я хочу передать -1 как thing_index
. На других языках это то, что вы ожидаете index()
, если он не сможет найти элемент. На самом деле он выбрасывает ValueError
.
Я мог бы сделать это:
try:
thing_index = thing_list.index(thing)
except ValueError:
thing_index = -1
otherfunction(thing_list, thing_index)
Но это кажется грязным, и я не знаю, может ли ValueError
подняться по какой-то другой причине. Я придумал следующее решение, основанное на функциях генератора, но оно кажется немного сложным:
thing_index = ( [(i for i in xrange(len(thing_list)) if thing_list[i]==thing)] or [-1] )[0]
Есть ли более чистый способ достичь того же? Предположим, что список не отсортирован.
Ответы
Ответ 1
Нет ничего "грязного" в использовании предложения try-except. Это питонический путь. ValueError
будет вызван только методом .index
, потому что это единственный код, который у вас есть!
Чтобы ответить на комментарий:
В Python проще просить прощения, чем получить разрешение философия хорошо установлена, а нет index
не будет поднимать этот тип ошибки для любых других проблем. Не то чтобы я мог думать о них.
Ответ 2
thing_index = thing_list.index(elem) if elem in thing_list else -1
Одна строка. Просто. Нет исключений.
Ответ 3
Тип dict
имеет получить
функцию, где, если ключ не существуют в словаре, второй аргумент get
- это значение, которое он должен вернуть. Аналогично существует setdefault
, который возвращает значение в dict
, если ключ существует, в противном случае он устанавливает значение в соответствии с вашим параметром по умолчанию и затем возвращает ваш параметр по умолчанию.
Вы можете расширить тип list
, чтобы иметь метод getindexdefault
.
class SuperDuperList(list):
def getindexdefault(self, elem, default):
try:
thing_index = self.index(elem)
return thing_index
except ValueError:
return default
Что можно было бы использовать как:
mylist = SuperDuperList([0,1,2])
index = mylist.getindexdefault( 'asdf', -1 )
Ответ 4
Нет ничего плохого в вашем коде, который использует ValueError
. Вот еще один лайнер, если вы хотите избежать исключений:
thing_index = next((i for i, x in enumerate(thing_list) if x == thing), -1)
Ответ 5
Этот вопрос является одной из языковых философий. В Java, например, всегда существовала традиция, что исключения действительно должны использоваться только в "исключительных обстоятельствах", когда произошли ошибки, а не для управления потоком. В начале это было по соображениям производительности, поскольку исключения Java были медленными, но теперь это стало принятым стилем.
В отличие от Python всегда использовал исключения, чтобы указать нормальный поток программы, например, повышение ValueError
, как мы обсуждаем здесь. В стиле Python нет ничего "грязного", и из этого есть еще много чего. Еще более распространенным примером является StopIteration
exception, который выражается методом next()
итератора, чтобы сигнализировать о том, что дополнительных значений нет.
Ответ 6
Как насчет этого:
otherfunction(thing_collection, thing)
Вместо того, чтобы выставлять что-то такое, зависящее от реализации, как индекс списка в функциональном интерфейсе, передавать коллекцию и вещь и позволять другим функциям разбираться с проблемами "тест для членства". Если другая функция записана как агностик типа коллекции, то она, вероятно, начнется с:
if thing in thing_collection:
... proceed with operation on thing
который будет работать, если thing_collection - это список, кортеж, набор или dict.
Это возможно яснее, чем:
if thing_index != MAGIC_VALUE_INDICATING_NOT_A_MEMBER:
который является кодом, который у вас уже есть в другой функции.
Ответ 7
Как насчет этого:
temp_inx = (L + [x]).index(x)
inx = temp_inx if temp_inx < len(L) else -1
Ответ 8
У меня такая же проблема с методом ".index()" в списках. У меня нет проблем с тем, что он генерирует исключение, но я категорически не согласен с тем, что это не описательный ValueError. Я мог бы понять, если бы это был IndexError.
Я вижу, почему возвращение "-1" было бы проблемой, потому что это правильный индекс в Python. Но реалистично, я никогда не ожидаю, что метод ".index()" возвращает отрицательное число.
Здесь идет один лайнер (хорошо, это довольно длинная строка...), проходит через список ровно один раз и возвращает "Нет", если элемент не найден. Было бы тривиально переписать его, чтобы вернуть -1, если вы этого пожелаете.
indexOf = lambda list, thing: \
reduce(lambda acc, (idx, elem): \
idx if (acc is None) and elem == thing else acc, list, None)
Как использовать:
>>> indexOf([1,2,3], 4)
>>>
>>> indexOf([1,2,3], 1)
0
>>>
Ответ 9
Если вы делаете это часто, то лучше сохранить это в виде вспомогательной функции:
def index_of(val, in_list):
try:
return in_list.index(val)
except ValueError:
return -1
Ответ 10
Как насчет этого?
li = [1,2,3,4,5] # create list
li = dict(zip(li,range(len(li)))) # convert List To Dict
print( li ) # {1: 0, 2: 1, 3: 2, 4:3 , 5: 4}
li.get(20) # None
li.get(1) # 0
Ответ 11
Я не знаю, почему вы думаете, что это грязно... из-за исключения? если вы хотите oneliner, вот он:
thing_index = thing_list.index(elem) if thing_list.count(elem) else -1
но я бы посоветовал не использовать его; Я считаю, что решение Росса Роджерса является лучшим, использовать объект для инкапсуляции вашего поведения desiderd, не пытайтесь подталкивать язык к его пределам за счет удобства чтения.
Ответ 12
Я бы предложил:
if thing in thing_list:
list_index = -1
else:
list_index = thing_list.index(thing)