找到列表中第n项的索引

kef*_*ich 39 python arrays indexing performance numpy

我想找到列表中项目第n次出现的索引.例如,

x=[False,True,True,False,True,False,True,False,False,False,True,False,True]
Run Code Online (Sandbox Code Playgroud)

第n个真实的索引是什么?如果我想要第五次出现(第四次,如果零索引),答案是10.

我想出来:

indargs = [ i for i,a in enumerate(x) if a ]
indargs[n]
Run Code Online (Sandbox Code Playgroud)

请注意,x.index在某个点之后返回第一次出现或第一次出现,因此据我所知,这不是解决方案.

对于类似于上述情况的情况,还有numpy的解决方案,例如使用cumsumwhere,但我想知道是否有一种无懈可击的方法来解决问题.

自从我第一次遇到这个问题以来,我一直关注性能,同时为项目Euler问题实现了Eratosthenes筛选,但这是我在其他情况下遇到的更普遍的问题.

编辑:我得到了很多很棒的答案,所以我决定做一些性能测试.以下是timeit具有len搜索第4000 /第1000真实的元素的列表的执行时间(以秒为单位).列表是随机的True/False.源代码链接如下; 这是一个混乱的触摸.我使用了海报名称的短/修改版本来描述除了listcomp上面的简单列表理解之外的函数.

True Test (100'th True in a list containing True/False)
         nelements      eyquem_occur eyquem_occurrence            graddy            taymon          listcomp       hettinger26         hettinger
             3000:          0.007824          0.031117          0.002144          0.007694          0.026908          0.003563          0.003563
            10000:          0.018424          0.103049          0.002233          0.018063          0.088245          0.003610          0.003769
            50000:          0.078383          0.515265          0.002140          0.078074          0.442630          0.003719          0.003608
           100000:          0.152804          1.054196          0.002129          0.152691          0.903827          0.003741          0.003769
           200000:          0.303084          2.123534          0.002212          0.301918          1.837870          0.003522          0.003601
True Test (1000'th True in a list containing True/False)
         nelements      eyquem_occur eyquem_occurrence            graddy            taymon          listcomp       hettinger26         hettinger
             3000:          0.038461          0.031358          0.024167          0.039277          0.026640          0.035283          0.034482
            10000:          0.049063          0.103241          0.024120          0.049383          0.088688          0.035515          0.034700
            50000:          0.108860          0.516037          0.023956          0.109546          0.442078          0.035269          0.035373
           100000:          0.183568          1.049817          0.024228          0.184406          0.906709          0.035135          0.036027
           200000:          0.333501          2.141629          0.024239          0.333908          1.826397          0.034879          0.036551
True Test (20000'th True in a list containing True/False)
         nelements      eyquem_occur eyquem_occurrence            graddy            taymon          listcomp       hettinger26         hettinger
             3000:          0.004520          0.004439          0.036853          0.004458          0.026900          0.053460          0.053734
            10000:          0.014925          0.014715          0.126084          0.014864          0.088470          0.177792          0.177716
            50000:          0.766154          0.515107          0.499068          0.781289          0.443654          0.707134          0.711072
           100000:          0.837363          1.051426          0.501842          0.862350          0.903189          0.707552          0.706808
           200000:          0.991740          2.124445          0.498408          1.008187          1.839797          0.715844          0.709063
Number Test (750'th 0 in a list containing 0-9)
         nelements      eyquem_occur eyquem_occurrence            graddy            taymon          listcomp       hettinger26         hettinger
             3000:          0.026996          0.026887          0.015494          0.030343          0.022417          0.026557          0.026236
            10000:          0.037887          0.089267          0.015839          0.040519          0.074941          0.026525          0.027057
            50000:          0.097777          0.445236          0.015396          0.101242          0.371496          0.025945          0.026156
           100000:          0.173794          0.905993          0.015409          0.176317          0.762155          0.026215          0.026871
           200000:          0.324930          1.847375          0.015506          0.327957          1.536012          0.027390          0.026657
Run Code Online (Sandbox Code Playgroud)

Hettinger的itertools解决方案几乎总是最好的.taymon和graddy的解决方案在大多数情况下都是最好的,但是当你想要第n个实例使得n为高或者列表中出现少于n次时,列表理解方法对于短数组可能更好.如果出现少于n次的可能性,则初始count检查可节省时间.此外,当搜索数字而不是真/假时,graddy的效率更高......不清楚为什么会这样.eyquem的解决方案基本上与其他解决方案相当,但开销略有增加或减少; eyquem_occur与taymon的解决方案大致相同,而eyquem_occurrence类似于listcomp.

Ray*_*ger 35

@Taymon使用list.index的答案很棒.

FWIW,这是使用itertools模块的功能方法.它适用于任何可迭代的输入,而不仅仅是列表:

>>> from itertools import compress, count, imap, islice
>>> from functools import partial
>>> from operator import eq

>>> def nth_item(n, item, iterable):
        indicies = compress(count(), imap(partial(eq, item), iterable))
        return next(islice(indicies, n, None), -1)
Run Code Online (Sandbox Code Playgroud)

这个例子很好,因为它展示了如何有效地结合Python的功能工具集.注意,一旦管道建立起来,就不会出现围绕Python的eval循环 - 所有内容都以C速度完成,内存占用空间很小,评估范围很小,没有可变赋值,还有可单独测试的组件.IOW,这是程序员梦寐以求的一切:-)

样品运行:

>>> x = [False,True,True,False,True,False,True,False,False,False,True,False,True]
>>> nth_item(50, True, x)
-1
>>> nth_item(0, True, x)
1
>>> nth_item(1, True, x)
2
>>> nth_item(2, True, x)
4
>>> nth_item(3, True, x)
6
Run Code Online (Sandbox Code Playgroud)

  • @keflavich我不知道一个简单的方法来反向运行2.7 itertools而不重建你的Python,但你可以实现纯Python等价,如2.7 itertools文档中所示.试试这个:``compress = lambda data,selectors:(d代表d,s代表izip(数据,选择器),如果s)``. (2认同)

Tay*_*mon 27

我不能肯定这是最快的方式,但我想它会很好:

i = -1
for j in xrange(n):
    i = x.index(True, i + 1)
Run Code Online (Sandbox Code Playgroud)

答案是i.

  • +1好工作.这是一个干净的解决方案,它最大限度地利用了*list.index*的*start*参数:-) (3认同)