在 Python 中,如何找到不是某个值的列表中第一项的索引?
Posted
技术标签:
【中文标题】在 Python 中,如何找到不是某个值的列表中第一项的索引?【英文标题】:In Python, how can I find the index of the first item in a list that is NOT some value? 【发布时间】:2011-02-14 10:46:46 【问题描述】:Python 的列表类型有一个 index(x) 方法。它接受一个参数 x,并返回列表中第一个值为 x 的项目的(整数)索引。
基本上,我需要反转 index(x) 方法。我需要获取列表中没有值 x 的第一个值的索引。我什至可以使用一个函数来返回第一个项目的索引,其值为 != None。
我可以想到一个带有递增计数器变量的“for”循环实现,但我觉得我错过了一些东西。是否有现有的方法或单行 Python 构造可以处理这个问题?
在我的程序中,当我处理从复杂的正则表达式匹配返回的列表时会出现这种情况。每个列表中除一项外的所有项目的值为无。如果我只需要匹配的字符串,我可以使用像“[x for x in [my_list] if x is not None]”这样的列表理解,但我需要索引来确定我的正则表达式中的哪个捕获组实际上导致了比赛。
【问题讨论】:
您确定需要索引而不是实际值吗? 列表推导与 for 循环基本相同,但以不同的方式编写(通常更难阅读)。我建议只使用 for 循环(使用枚举) 【参考方案1】:在第一场比赛中退出真的很容易:不要计算完整的列表理解(然后丢弃除第一项之外的所有内容),而是使用 next
而不是 genexp。例如假设你想要-1
,当没有项目满足!= x
的条件时,
return next((i for i, v in enumerate(L) if v != x), -1)
这是 Python 2.6 的语法;如果您坚持使用 2.5 或更早版本,.next()
是 genexp(或其他迭代器)的一种方法,并且不接受像上面的 -1
这样的默认值(所以如果您不想看到 @ 987654328@ 例外,您必须使用try
/except
)。但是,有在 2.5 之后发布了更多版本的原因 - 语言及其内置的不断改进!-)
【讨论】:
我实际上不需要处理“没有满足”条件,因为正则表达式方法总是返回至少一个非无列表项。所以我认为这应该有效:next(i for i, x in enumerate(my_list, ) if x is not None)。在调试器下,它似乎在第一场比赛就停止了,所以我被卖了。很酷的把戏。 @Ryan,是的,如果您在所有项目都为 None 时不需要默认结果,那么您更简单的表达式就可以正常工作。【参考方案2】:当您只需要第一个时使用列表推导式(对我来说)感觉很糟糕。使用 for 循环并提前退出。
>>> lst = [None, None, None, "foo", None]
>>> for i, item in enumerate(lst):
... if item: break
... else:
... print "not found"
...
>>> i
3
【讨论】:
您是否阅读了我最初问题中的第 3 段? for 循环的实现是微不足道的。我专门寻找单线或现有方法。 (不过,根据投票结果,您似乎不是唯一一个没有抓住重点的人。我应该让它更明显一点。) @Ryan B. Lynch:我确实读过。你提到你可以使用for循环和计数器来做到这一点......这是更多的代码而且有点难看。我使用 enumerate() 来自动获取计数器。根据您的问题,我不确定您是否知道 enumerate 存在。 OTOH,我不知道 next() 存在(但我一直使用 python 2.5),所以我从 Alex 的解决方案中学到了一些东西。我不知道为什么人们投票支持这个,也许投票来自试图在一条线上做一些可以简单而透明地在两条线中完成的事情? 关于柜台与破坏的好点。至于关于“尝试在一条线上做一些可以在两条线中轻松透明地完成的事情”的意见,您的原始答案非常清楚地表达了这一点。但是,如果编码风格的考虑激发了你的反应,为什么要让它成为一个答案呢?这不是 cmets 的用途吗? @Ryan B. Lynch:编码风格并没有激发我的反应 - 动机 1:使用列表理解(构建所有结果的列表)并返回第一个是浪费的。动机 2: enumerate() 有助于做你想做的事。好的动机3:在for循环中真的很明显:)就目前而言,它是您问题的可能解决方案,所以我认为它合理地属于答案。很抱歉,这不是您要找的答案,我很高兴 Alex 提供了这个答案。 :) 你读过关于这个的元线程(meta.stackexchange.com/questions/18552/…)吗?你有一个非常好的答案,但这不是我的问题的答案,在这里。【参考方案3】:enumerate()
返回一个迭代器,它产生一个由可迭代对象的当前索引和项目本身组成的元组。
【讨论】:
噢,我真的错过了什么。是的,确切的用法是这样的:[i for i, x in enumerate(my_list) if x is not None]。谢谢!【参考方案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 循环更好的地步。即使是上述解决方案也没有 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
计数 :)
【讨论】:
请注意,在某些情况下,item.__ne__
可以用来代替上面的ft.partial(op.ne, item)
设备;但是,后者适用于所有item
s。
这真是令人难以理解。以上是关于在 Python 中,如何找到不是某个值的列表中第一项的索引?的主要内容,如果未能解决你的问题,请参考以下文章