在python中处理list.index(可能不存在)的最佳方法?

问题:在python中处理list.index(可能不存在)的最佳方法?

我有看起来像这样的代码:

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]

有没有一种更清洁的方法来实现同一目标?假设列表未排序。

I have code which looks something like this:

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

ok so that’s simplified but you get the idea. Now thing might not actually be in the list, in which case I want to pass -1 as thing_index. In other languages this is what you’d expect index() to return if it couldn’t find the element. In fact it throws a ValueError.

I could do this:

try:
    thing_index = thing_list.index(thing)
except ValueError:
    thing_index = -1
otherfunction(thing_list, thing_index)

But this feels dirty, plus I don’t know if ValueError could be raised for some other reason. I came up with the following solution based on generator functions, but it seems a little complex:

thing_index = ( [(i for i in xrange(len(thing_list)) if thing_list[i]==thing)] or [-1] )[0]

Is there a cleaner way to achieve the same thing? Let’s assume the list isn’t sorted.


回答 0

使用try-except子句没有任何“肮脏”。这是Python方式。ValueError只会由.index方法引发,因为这是您唯一的代码!

要回答的评论:
在Python,容易请求原谅比获得许可的理念已经非常成熟,并没有 index不会提高这种类型的错误的任何其他问题。并不是我能想到的。

There is nothing “dirty” about using try-except clause. This is the pythonic way. ValueError will be raised by the .index method only, because it’s the only code you have there!

To answer the comment:
In Python, easier to ask forgiveness than to get permission philosophy is well established, and no index will not raise this type of error for any other issues. Not that I can think of any.


回答 1

thing_index = thing_list.index(elem) if elem in thing_list else -1

一条线。简单。没有exceptions。

thing_index = thing_list.index(elem) if elem in thing_list else -1

One line. Simple. No exceptions.


回答 2

dict类型具有一个get函数,如果字典中不存在该键,则to的第二个参数get是它应返回的值。同样setdefaultdict存在,如果键存在,则返回值;否则,它将根据您的默认参数设置值,然后返回您的默认参数。

您可以扩展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 )

The dict type has a get function, where if the key doesn’t exist in the dictionary, the 2nd argument to get is the value that it should return. Similarly there is setdefault, which returns the value in the dict if the key exists, otherwise it sets the value according to your default parameter and then returns your default parameter.

You could extend the list type to have a getindexdefault method.

class SuperDuperList(list):
    def getindexdefault(self, elem, default):
        try:
            thing_index = self.index(elem)
            return thing_index
        except ValueError:
            return default

Which could then be used like:

mylist = SuperDuperList([0,1,2])
index = mylist.getindexdefault( 'asdf', -1 )

回答 3

使用的代码没有错ValueError。如果您想避免exceptions,这里还有另外一种说法:

thing_index = next((i for i, x in enumerate(thing_list) if x == thing), -1)

There is nothing wrong with your code that uses ValueError. Here’s yet another one-liner if you’d like to avoid exceptions:

thing_index = next((i for i, x in enumerate(thing_list) if x == thing), -1)

回答 4

这个问题是语言哲学之一。例如,在Java中,一直存在这样一种传统,即异常仅应仅在发生错误的“exceptions情况”中使用,而不是用于流控制。最初,这是出于性能原因,因为Java异常的速度很慢,但是现在这已成为公认的样式。

相反,Python一直使用异常来指示正常的程序流,就像ValueError我们在这里讨论的那样抛出异常。Python风格对此没有任何“污秽”,并且还有更多的来源。一个更常见的例子是StopIteration异常,它是由迭代器的next()方法引发的,以表示没有其他值。

This issue is one of language philosophy. In Java for example there has always been a tradition that exceptions should really only be used in “exceptional circumstances” that is when errors have happened, rather than for flow control. In the beginning this was for performance reasons as Java exceptions were slow but now this has become the accepted style.

In contrast Python has always used exceptions to indicate normal program flow, like raising a ValueError as we are discussing here. There is nothing “dirty” about this in Python style and there are many more where that came from. An even more common example is StopIteration exception which is raised by an iterator‘s next() method to signal that there are no further values.


回答 5

如果您经常这样做,那么最好在辅助功能中将其烘烤掉:

def index_of(val, in_list):
    try:
        return in_list.index(val)
    except ValueError:
        return -1 

If you are doing this often then it is better to stove it away in a helper function:

def index_of(val, in_list):
    try:
        return in_list.index(val)
    except ValueError:
        return -1 

回答 6

那😃呢?

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 

What about this 😃 :

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 

回答 7

那这个呢:

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:

这是您在其他功能中已经拥有的代码。

What about this:

otherfunction(thing_collection, thing)

Rather than expose something so implementation-dependent like a list index in a function interface, pass the collection and the thing and let otherfunction deal with the “test for membership” issues. If otherfunction is written to be collection-type-agnostic, then it would probably start with:

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

which will work if thing_collection is a list, tuple, set, or dict.

This is possibly clearer than:

if thing_index != MAGIC_VALUE_INDICATING_NOT_A_MEMBER:

which is the code you already have in otherfunction.


回答 8

像这样:

temp_inx = (L + [x]).index(x) 
inx = temp_inx if temp_inx < len(L) else -1

What about like this:

temp_inx = (L + [x]).index(x) 
inx = temp_inx if temp_inx < len(L) else -1

回答 9

列表中的“ .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
>>>

I have the same issue with the “.index()” method on lists. I have no issue with the fact that it throws an exception but I strongly disagree with the fact that it’s a non-descriptive ValueError. I could understand if it would’ve been an IndexError, though.

I can see why returning “-1” would be an issue too because it’s a valid index in Python. But realistically, I never expect a “.index()” method to return a negative number.

Here goes a one liner (ok, it’s a rather long line …), goes through the list exactly once and returns “None” if the item isn’t found. It would be trivial to rewrite it to return -1, should you so desire.

indexOf = lambda list, thing: \
            reduce(lambda acc, (idx, elem): \
                   idx if (acc is None) and elem == thing else acc, list, None)

How to use:

>>> indexOf([1,2,3], 4)
>>>
>>> indexOf([1,2,3], 1)
0
>>>

回答 10

我不知道为什么你应该认为它很脏…因为异常?如果您想要一个内衬,则为:

thing_index = thing_list.index(elem) if thing_list.count(elem) else -1

但是我建议不要使用它。我认为Ross Rogers解决方案是最好的解决方案,请使用对象封装您的喜好行为,不要尝试以牺牲可读性为代价将语言推向极限。

I don’t know why you should think it is dirty… because of the exception? if you want a oneliner, here it is:

thing_index = thing_list.index(elem) if thing_list.count(elem) else -1

but i would advise against using it; I think Ross Rogers solution is the best, use an object to encapsulate your desiderd behaviour, don’t try pushing the language to its limits at the cost of readability.


回答 11

我建议:

if thing in thing_list:
  list_index = -1
else:
  list_index = thing_list.index(thing)

I’d suggest:

if thing in thing_list:
  list_index = -1
else:
  list_index = thing_list.index(thing)