如何在Python中使用正则表达式查找列表中项的索引?

4

I have a list like that:

lst = ['something', 'foo1', 'bar1', 'blabla', 'foo2']

使用正则表达式和 lst.index() ,是否可能获取第一个以“foo”(foo1)开头的项目的索引呢?

ind = lst.index("some_regex_for_the_item_starting_with_foo") ?

我知道可以创建一个计数器和一个for循环,然后使用方法startswith()。不过我想知道是否有更短更优美的方式。

5个回答

3

我认为如果startswith方法能够满足您的需求,那么可以使用它(我不确定您是否真的需要在这里使用正则表达式 - 但是下面的代码可以轻松地修改为使用正则表达式):

data = ['text', 'foo2', 'foo1', 'sample']
indeces = (i for i,val in enumerate(data) if val.startswith('foo'))

或者使用正则表达式:
from re import match
data = ['text', 'foo2', 'foo1', 'sample']
indeces = (i for i,val in enumerate(data) if match('foo', val))

1

使用lst.index无法实现,但是这里有一种替代方法,可能比for循环更优雅:

try:
    ind = (i for i, v in enumerate(lst) if v.startswith("foo")).next()
except StopIteration:
    ind = -1   # or however you want to say that the item wasn't found

正如senderle在评论中指出的那样,可以通过使用具有默认值的next()内置函数(2.6+)来将其缩短为一行:
ind = next((i for i, v in enumerate(lst) if v.startswith("foo")), -1)

1
很遗憾,list.index 没有 key 参数。如果有的话,解决方案可能会是:
# warning: NOT working code
result = L.index(True, key=lambda x: regexp.match(x) is not None)

此外,鉴于我刚刚发现在 Python 社区中,lambda 显然被认为是一种可憎的东西,我不确定未来是否会添加更多的 key 参数。

你不觉得在没有使用 lambda 的情况下,key 是有用的吗?例如,使用 operator.itemgetter。我也很好奇,谁认为 lambda 是可恶的。当然,它可能确实不够优雅,但我认为它是语言中的一个重要部分,特别是当你有一个内置函数不能完全满足你的需求时。 - senderle
@senderle:是的,key在其他情况下可能很有用,但在许多常见情况下,使用一个小的匿名闭包就足够了。至于为什么lambda这么受人憎恶,我最近才发现(在EuroPython上),我问为什么在一个应该使用lambda的例子中使用了function.Partial,Alex Martelli回答说:“唯一合理的包含'lambda'和'should'两个词的短语是'lambda should be removed from Python'”。更详细的解释请参见https://dev59.com/b3A75IYBdhLWcg3wg5Zh。 - 6502
谢谢,这让我明白了。我认为在这种情况下,实用性胜过纯粹性(对我来说)。我理解AM的观点,虽然如果“lambda”被移除,我想我不会太难过。 - senderle

0

如果有这样的内置功能会很酷。但 Python 没有这个功能。使用 itertools 有一些有趣的解决方案。(这也让我希望有一个 itertools.takewhile_false。如果存在,这些代码将更易读。)

>>> from itertools import takewhile
>>> import re
>>> m = re.compile('foo.*')
>>> print len(tuple(itertools.takewhile(lambda x: not m.match(x), lst)))
1

这是我的第一个想法,但它需要您创建一个临时元组并获取其长度。然后我想到,您可以只做一个简单的求和,避免使用临时列表:

>>> print sum(1 for _ in takewhile(lambda x: not m.match(x), lst))
1

但这也有点麻烦。如果可能的话,我更喜欢避免使用一次性变量。让我们再试一次。

>>> sum(takewhile(bool, (not m.match(x) for x in lst)))
1

好多了。


你的解决方案非常出色,但同时也不太易读,不过我明白你的意思了。我猜使用“not”而不是使用函数takewhile_false更自然一些。同样的事情也适用于while_false循环,而不是“while smth != smth2”。 - rightaway717
我在itertools中找到了“dropwhile”。我想这就是你所说的“takewhile_false”的意思。 - rightaway717
@rightaway717,dropwhile会_丢弃_直到谓词为真的项目,然后获取其余部分,就像takewhile 获取 直到谓词为真的项目并丢弃其余部分一样。换句话说,对于相同的可迭代对象和谓词, takewhile将产生列表的前半部分,而dropwhile将产生列表的后半部分。 - senderle
抱歉,但这太糟糕了,你正在构建一个元组(可能很大),只是为了计算索引? - alexis
@alexis,嗯,这就是为什么我改进了第一个版本,如果你读完整篇文章肯定会看到的。后来的版本不会创建元组。我想sum内部可能会构建一个元组 - 如果是这样,那我必须对sum的实现提出异议。 - senderle
@senderle:抱歉,我错过了你自己提到元组的那部分。takewhilesum不会构建一个元组。 - alexis

0
l = ['something', 'foo1', 'bar1', 'blabla', 'foo2']
l.index(filter(lambda x:x.startswith('foo'),l)[0])

我会记住这个解决方案。我刚开始学习Python,不知道它与“i for i,val in ...”意思相同。现在我知道了。感谢您的努力。 - rightaway717

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接