【问题标题】:How to find the last occurrence of an item in a Python list如何在 Python 列表中查找最后一次出现的项目
【发布时间】:2011-10-16 22:31:15
【问题描述】:

假设我有这个清单:

li = ["a", "b", "a", "c", "x", "d", "a", "6"]

就帮助显示我而言,没有返回最后一次出现的字符串的内置函数(如index 的反面)。所以基本上,我怎样才能在给定的列表中找到"a" 的最后一次出现?

【问题讨论】:

    标签: python list last-occurrence


    【解决方案1】:

    如果您实际上只使用示例中所示的单个字母,那么str.rindex 将很方便。这会引发ValueError,如果没有这样的项目,则会引发与list.index 相同的错误类。演示:

    >>> li = ["a", "b", "a", "c", "x", "d", "a", "6"]
    >>> ''.join(li).rindex('a')
    6
    

    对于更一般的情况,您可以在反向列表中使用list.index:

    >>> len(li) - 1 - li[::-1].index('a')
    6
    

    这里的切片创建了整个列表的副本。这对于短列表来说很好,但对于 li 非常大的情况,使用惰性方法可以提高效率:

    def list_rindex(li, x):
        for i in reversed(range(len(li))):
            if li[i] == x:
                return i
        raise ValueError("{} is not in list".format(x))
    

    单行版本:

    next(i for i in reversed(range(len(li))) if li[i] == 'a')
    

    【讨论】:

    • YMMV,但是对于这个例子,len(li) - next(i for i, v in enumerate(reversed(li), 1) if v == 'a') 对我来说要快一点
    • 有str.rindex(),为什么没有list.rindex()?
    • @Chris_Rands: 比range(len(li)-1, -1, -1) 更好的是reversed(range(len(li))) 或range(len(li))[::-1](它们也大致相同,不像reversed 和反转切片之间的大多数比较;现代Py3 range可以反向切片以制作另一个向后运行的懒惰range,因此它具有同样的性能)。看起来 wim 选择了前者。
    • @ShadowRanger 是的,wim 编辑了他的答案,因为我写了那条评论。这是当时的答案stackoverflow.com/revisions/… 我将删除我之前的评论(和这个)以避免混淆
    • Pythonic 版本next(len(a)-i-1 for i, x in enumerate(reversed(a)) if x == 3)
    【解决方案2】:

    类似于 Ignacio 的单线,但更简单/更清晰

    max(loc for loc, val in enumerate(li) if val == 'a')
    

    对我来说,这似乎非常清晰和 Pythonic:您正在寻找包含匹配值的最高索引。不需要 nexts、lambdas、reverseds 或 itertools。

    【讨论】:

    • 正如@Isaac 指出的那样,这总是迭代 li 的所有 N 个元素。
    • 这是完美的。对于大型数据集可能并不理想,但对于少量数据来说它很棒。
    • 一个显着的缺点是您将始终遍历整个列表。您应该在回答中强调这一点。
    【解决方案3】:

    许多其他解决方案需要遍历整个列表。这没有。

    def find_last(lst, elm):
      gen = (len(lst) - 1 - i for i, v in enumerate(reversed(lst)) if v == elm)
      return next(gen, None)
    

    编辑:事后看来,这似乎是不必要的巫术。我会这样做:

    def find_last(lst, sought_elt):
        for r_idx, elt in enumerate(reversed(lst)):
            if elt == sought_elt:
                return len(lst) - 1 - r_idx
    

    【讨论】:

    • 我怀疑区别在于 C 循环与 Python 循环。
    【解决方案4】:
    >>> (x for x in reversed([y for y in enumerate(li)]) if x[1] == 'a').next()[0]
    6
    
    >>> len(li) - (x for x in (y for y in enumerate(li[::-1])) if x[1] == 'a').next()[0] - 1
    6
    

    【讨论】:

    • 为什么不reversed(enumerate(li))?
    • 因为3年前我没有想到。
    • 奇怪的是,reversed(enumerate(li)) 会导致一个错误为argument to reversed() must be a sequence!它对reversed((y for y in enumarete(li)) 也这么说!
    • reversed() 不能对一般的迭代器(包括生成器)进行操作是有道理的。因此,enumerate(reversed(li)) 并调整枚举元组的索引组件是一种避免创建列表副本的解决方法。
    【解决方案5】:

    我喜欢wim's 和Ignacio's 的答案。然而,我认为itertools 提供了一个更易读的替代方案,尽管有 lambda。 (对于 Python 3;对于 Python 2,使用 xrange 而不是 range)。

    >>> from itertools import dropwhile
    >>> l = list('apples')
    >>> l.index('p')
    1
    >>> next(dropwhile(lambda x: l[x] != 'p', reversed(range(len(l)))))
    2
    

    如果找不到该项目,这将引发StopIteration 异常;你可以抓住它并提出ValueError,以使其行为just like index。

    定义为函数,避免使用lambda 快捷方式:

    def rindex(lst, item):
        def index_ne(x):
            return lst[x] != item
        try:
            return next(dropwhile(index_ne, reversed(range(len(lst)))))
        except StopIteration:
            raise ValueError("rindex(lst, item): item not in list")
    

    它也适用于非字符。已测试:

    >>> rindex(['apples', 'oranges', 'bananas', 'apples'], 'apples')
    3
    

    【讨论】:

    • Python 3 现在允许将默认 arg 设置为 next,因此您可以消除 try... except
    • @PM2Ring,我不知道你为什么要在这里使用默认参数。然后你需要有一个if 声明并在其中提出一个ValueError。 (回想一下,我们正试图完全复制index API,这意味着如果找不到该项目,则提高ValueError。)在这种情况下使用try 更惯用,我猜想更多高效。
    • 公平通话。也许提高IndexError而不是ValueError,以与.index保持一致?
    • IndexError 用于传递不正确的索引。将缺失值传递给 index 会生成 ValueError。
    【解决方案6】:

    与dict

    您可以使用字典键是唯一的这一事实,并且在使用元组构建字典时,只会使用特定键的最后一个值分配。正如其他答案中所述,这对于小型列表来说很好,但它会为所有唯一值创建一个字典,并且对于大型列表可能效率不高。

    dict(map(reversed, enumerate(li)))["a"]
    
    6
    

    【讨论】:

      【解决方案7】:

      我来这里是希望找到有人已经完成了编写list.rindex最高效版本的工作,它提供了list.index的完整接口(包括可选的start和stop参数)。我没有在这个问题的答案中找到这一点,或者here,或者here,或者here。所以我自己把它放在一起......利用其他答案和其他问题的建议。

      def rindex(seq, value, start=None, stop=None):
        """L.rindex(value, [start, [stop]]) -> integer -- return last index of value.
        Raises ValueError if the value is not present."""
        start, stop, _ = slice(start, stop).indices(len(seq))
        if stop == 0:
          # start = 0
          raise ValueError('{!r} is not in list'.format(value))
        else:
          stop -= 1
          start = None if start == 0 else start - 1
        return stop - seq[stop:start:-1].index(value)
      

      在其他几个答案中建议使用len(seq) - 1 - next(i for i,v in enumerate(reversed(seq)) if v == value) 的技术可以更节省空间:它不需要创建完整列表的反向副本。但在我的(临时的、随意的)测试中,它慢了大约 50%。

      【讨论】:

        【解决方案8】:

        使用简单的循环:

        def reversed_index(items, value):
            for pos, curr in enumerate(reversed(items)):
                if curr == value:
                    return len(items) - pos - 1
            raise ValueError("{0!r} is not in list".format(value))
        

        【讨论】:

          【解决方案9】:
          last_occurence=len(yourlist)-yourlist[::-1].index(element)-1
          

          就这么简单。无需导入或创建函数。

          【讨论】:

            【解决方案10】:
            lastIndexOf = lambda array, item: len(array) - (array[::-1].index(item)) - 1
            

            【讨论】:

              【解决方案11】:

              如果列表很小,您可以计算所有索引并返回最大的:

              index = max(i for i, x in enumerate(elements) if x == 'foo')
              

              【讨论】:

                【解决方案12】:

                这是一个查找列表中元素最后一次出现的函数。一个列表和一个元素被传递给函数。

                li = ["a", "b", "a", "c", "x", "d", "a", "6"]
                element = "a"
                
                def last_occurrence(li,element):
                    for i in range(len(li)-1,0,-1):
                        if li[i] == element:
                            return i
                
                    return -1
                
                last_occ = last_occurrence(li, element)
                if (last_occ != -1):
                    print("The last occurrence at index : ",last_occ)
                else:
                    print("Element not found")
                

                在last_occurrence 函数内部,for 循环与range 一起使用。这将以相反的顺序迭代列表。如果当前索引的元素与searched 元素匹配,则函数将返回index。 如果在比较列表中的所有元素后,searched 元素未找到函数将返回 -1。

                【讨论】:

                  【解决方案13】:
                  def rindex(lst, val):
                      try:
                          return next(len(lst)-i for i, e in enumerate(reversed(lst), start=1) if e == val)
                      except StopIteration:
                          raise ValueError('{} is not in list'.format(val))
                  

                  【讨论】:

                    【解决方案14】:

                    val = [1,2,2,2,2,2,4,5]。

                    如果你需要找到 2 的最后出现

                    last_occurence = (len(val) -1) - list(reversed(val)).index(2)

                    【讨论】:

                      【解决方案15】:

                      这里有一个简单的方法来获取最后一个索引,使用enumerate 和列表理解:

                      li = ["a", "b", "a", "c", "x", "d", "a", "6"]
                      [l[0] for l in enumerate(li) if l[1] == "a"][-1]
                      

                      【讨论】:

                        猜你喜欢
                        • 2016-03-30
                        • 1970-01-01
                        • 1970-01-01
                        • 2020-04-19
                        • 2011-10-22
                        • 2020-09-08
                        • 2020-11-10
                        • 2012-07-31
                        相关资源
                        最近更新 更多