Лучший способ обработать list.index (может не существовать) в Python? - PullRequest
88 голосов
/ 25 января 2010

У меня есть код, который выглядит примерно так:

thing_index = thing_list.index(thing)
otherfunction(thing_list, thing_index)

хорошо, так что это упрощено, но вы поняли идею. Теперь 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]

Есть ли более чистый способ достичь того же? Давайте предположим, что список не отсортирован.

Ответы [ 12 ]

56 голосов
/ 25 января 2010

Нет ничего "грязного" в использовании предложения try-кроме. Это питонский путь. ValueError будет вызываться только методом .index, потому что это единственный код, который у вас есть!

Чтобы ответить на комментарий:
В Python проще попросить прощения, чем получить разрешение философия хорошо известна, и no index не вызовет этот тип ошибки для любых других проблем , Не то чтобы я мог думать о любом.

42 голосов
/ 25 января 2010
thing_index = thing_list.index(elem) if elem in thing_list else -1

Одна строка. Просто. Без исключений.

15 голосов
/ 25 января 2010

Тип dict имеет функцию get , где, если ключ не существует в словаре, вторым аргументом 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 )
5 голосов
/ 25 января 2010

Нет ничего плохого в вашем коде, который использует ValueError. Вот еще одна строка, если вы хотите избежать исключений:

thing_index = next((i for i, x in enumerate(thing_list) if x == thing), -1)
3 голосов
/ 25 января 2010

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

Напротив, Python всегда использовал исключения, чтобы указать нормальный ход программы, например, подняв ValueError, как мы здесь обсуждаем. В стиле Python нет ничего «грязного», и есть много других, откуда это пришло. Еще более распространенный пример - StopIteration исключение , которое вызывается методом next() итератора, чтобы сигнализировать об отсутствии других значений.

1 голос
/ 15 февраля 2019

Как насчет этого:

temp_inx = (L + [x]).index(x) 
inx = temp_inx if temp_inx < len(L) else -1
1 голос
/ 25 января 2010

Что по этому поводу:

otherfunction(thing_collection, thing)

Вместо того, чтобы выставлять что-то, зависящее от реализации, например, индекс списка в интерфейсе функции, передавайте коллекцию и прочее и позволяйте другой функции решать проблемы «проверки на членство». Если другая функция написана как независимая от типа коллекции, то она, вероятно, будет начинаться с:

if thing in thing_collection:
    ... proceed with operation on thing

, который будет работать, если thing_collection является списком, кортежем, набором или диктом.

Возможно, это яснее, чем:

if thing_index != MAGIC_VALUE_INDICATING_NOT_A_MEMBER:

код, который у вас уже есть в другой функции.

0 голосов
/ 15 июня 2019

Как насчет этого ?:

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 
0 голосов
/ 28 марта 2018

Если вы делаете это часто, то лучше сохранить его с помощью вспомогательной функции:

def index_of(val, in_list):
    try:
        return in_list.index(val)
    except ValueError:
        return -1 
0 голосов
/ 18 января 2014

У меня та же проблема с методом ".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
>>>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...