【问题标题】:How to find an index of an item in a list, searching the item with a regular expression in Python?如何在列表中查找项目的索引,在 Python 中使用正则表达式搜索项目?
【发布时间】:2011-09-30 18:52:27
【问题描述】:

我有一个这样的列表:

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

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

ind = lst.index("some_regex_for_the_item_starting_with_foo") ?

我知道我可以创建一个计数器和一个 for 循环并使用方法 startswith()。 如果我错过了一些更短更优雅的方式,我很好奇。

【问题讨论】:

    标签: python regex list indexing


    【解决方案1】:

    我认为没关系,如果它执行您真正想要的操作,您可以使用startswith 方法(我不确定您是否真的需要regEx - 但是可以轻松修改下面的代码以使用regEx):

    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))
    

    【讨论】:

      【解决方案2】:

      使用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)
      

      【讨论】:

        【解决方案3】:

        不,很遗憾,list.index 没有 key 参数。 有一个解决方案可能是

        # warning: NOT working code
        result = L.index(True, key=lambda x: regexp.match(x) is not None)
        

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

        【讨论】:

        • 你不认为key 没有 lambda 有用吗?以operator.itemgetter 为例?我也很好奇谁认为lambda 是可憎的。当然,它可能真的很难看,但我认为它是语言的重要组成部分,尤其是当你有一个不能完全完成你想要的内置函数时。
        • @senderle: 是的key 可以用于其他情况,但在许多常见情况下,使用小的匿名闭包非常适合key。关于为什么 lambda 如此讨厌,我最近(在 EuroPython)发现了这一点,我问为什么在一个例子中 function.Partial 被用于应该是 lambda 的工作的案例中,Alex Martelli 回答 >。更多解释请参见stackoverflow.com/q/3252228/320726
        • 谢谢,这为我解决了问题。我认为这是(对我而言)实用性胜过纯度的情况。不过,我看到了 AM 的一面。如果lambda 被删除,我想我不会哭(太难了)。
        【解决方案4】:

        内置这样的东西会很酷。但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”
        • 我在 itertools 中找到了“dropwhile”。我想这就是你所说的“takewhile_false”
        • @rightaway717,不,dropwhile 丢弃项直到谓词为真,然后取出其余的,就像takewhile 取出直到谓词为真并丢弃其余的项。换句话说,给定相同的迭代和谓词,takewhile 将产生列表的第一部分,dropwhile 将产生列表的第二部分。
        • 抱歉,这很糟糕,您正在构建一个元组(可能很大)只是为了计算索引?
        • @alexis,嗯,这就是我改进第一个版本的原因,如果你阅读了整篇文章,你肯定已经看到了。更高版本不创建元组。我想sum 可能会在内部构建一个元组——在这种情况下,我必须对sum 的实现提出异议。
        【解决方案5】:
        l = ['something', 'foo1', 'bar1', 'blabla', 'foo2']
        l.index(filter(lambda x:x.startswith('foo'),l)[0])
        

        【讨论】:

        • 我会记住这个解决方案。我刚开始学习python,并不知道它与“i for i,val in ...”的含义相同。现在我知道了。感谢您的努力
        猜你喜欢
        • 1970-01-01
        • 2016-01-25
        • 2014-10-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-11
        • 2010-09-15
        相关资源
        最近更新 更多