web-dev-qa-db-ja.com

リストのn番目のアイテムのインデックスを見つける

リスト内のn番目のアイテムのインデックスを検索したい。例えば。、

x=[False,True,True,False,True,False,True,False,False,False,True,False,True]

N番目の真のインデックスは何ですか? 5回目(インデックスが0の場合は4回目)が必要な場合、答えは10です。

私は思いついた:

indargs = [ i for i,a in enumerate(x) if a ]
indargs[n]

ご了承ください x.indexは、最初の出現、またはあるポイントの後の最初の出現を返すため、私が知る限り、解決策ではありません。

上記と同様の場合のnumpyの解決策もあります。 cumsumwhereを使用しますが、問題を解決するための無数の方法があるかどうか知りたいのですが。

Project Euler 問題のためにSieve of Eratosthenesを実装したときに最初にこれに遭遇して以来、パフォーマンスが心配ですが、これは他の状況で遭遇したより一般的な質問です。

編集:私はたくさんの素晴らしい答えを得たので、私はいくつかのパフォーマンステストを行うことにしました。以下は、4000番目/ 1000番目のTrueを検索するtimeit要素を持つリストのlen実行時間(秒単位)です。リストはランダムな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

ヘッティンガーのitertoolsソリューションはほとんどの場合最高です。 taymonとgraddyのソリューションは、ほとんどの状況で次善の策ですが、リストの理解のアプローチは、nが高いようなn番目のインスタンスまたはn未満のリストがある場合に短い配列に適しています。発生回数がn回未満である可能性がある場合は、最初のcountチェックで時間を節約できます。また、True/Falseの代わりに数字を検索する場合は、graddyの方が効率的です...その理由は明確ではありません。 eyquemのソリューションは、基本的に他のソリューションと同等ですが、オーバーヘッドが多少異なります。 eyquem_occurrenceはlistcompに似ていますが、eyquem_occurはテイモンのソリューションとほぼ同じです。

39
keflavich

list.indexを使用した@Taymonからの回答は素晴らしかったです。

FWIW、これが itertools module を使用した機能的なアプローチです。リストだけでなく、反復可能な入力でも機能します。

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

この例は、Pythonの機能ツールセットを効果的に組み合わせる方法を示しているためNiceです。パイプラインがセットアップされると、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
35

これが最速の方法であるとは断言できませんが、かなり良いと思います。

i = -1
for j in xrange(n):
    i = x.index(True, i + 1)

答えはiです。

27
Taymon

効率が問題である場合、O(N)をとるリスト内包ではなく、通常(O(L))を繰り返すほうがよいと思います。ここで、Lはリストの長さです。

例:非常に大きなリストを考えて、最初の発生を見つけたいN = 1最初の発生を見つけたらすぐに停止するのが明らかに良い

count = 0
for index,i in enumerate(L):
    if i:
        count = count + 1
        if count==N:
            return index
2
Graddy

パフォーマンスに関心がある場合は、アルゴリズムによる最適化が可能かどうかを確認するのが最善です。たとえば、同じ値でこの関数を何度も呼び出す場合は、以前の計算をキャッシュすることができます(たとえば、要素の50番目のオカレンスを見つけたら、O(1)時間で以前のオカレンスを見つけることができます。 )。

それ以外の場合は、テクニックが(遅延)イテレーターで機能することを確認する必要があります。

私がそれを実装することを考えることができる最も* in *エレガントでパフォーマンスに満足している方法は次のとおりです:

_def indexOfNthOccurrence(N, element, stream):
    """for N>0, returns index or None"""
    seen = 0
    for i,x in enumerate(stream):
        if x==element:
            seen += 1
            if seen==N:
                return i
_

(列挙と他の手法のパフォーマンスの違いを本当に気にする場合は、特にCに頼る可能性のあるnumpy関数を使用して、プロファイリングに頼る必要があります)

ストリーム全体を前処理し、O(1)クエリをサポートするには:

_from collections import *
cache = defaultdict(list)
for i,elem in enumerate(YOUR_LIST):
    cache[elem] += [i]

# e.g. [3,2,3,2,5,5,1]
#       0 1 2 3 4 5 6
# cache: {3:[0,2], 1:[6], 2:[1,3], 5:[4,5]}
_
2
ninjagecko

最初にリストオブジェクトを作成し、このリストのn番目の1要素を返すソリューション:function occurence()

そして、私はそれらを愛しているので、ジェネレーターを使用して、関数型プログラマーの夢も満たすソリューションだと思います:function occur()

S = 'stackoverflow.com is a fantastic amazing site'
print 'object S is string %r' % S
print "indexes of 'a' in S :",[indx for indx,elem in enumerate(S) if elem=='a']

def occurence(itrbl,x,nth):
    return [indx for indx,elem in enumerate(itrbl)
            if elem==x ][nth-1] if x in itrbl \
           else None

def occur(itrbl,x,nth):
    return (i for pos,i in enumerate(indx for indx,elem in enumerate(itrbl)
                                     if elem==x)
            if pos==nth-1).next() if x in itrbl\
            else   None

print "\noccurence(S,'a',4th) ==",occurence(S,'a',4)
print "\noccur(S,'a',4th) ==",occur(S,'a',4)

結果

object S is string 'stackoverflow.com is a fantastic amazing site'
indexes of 'a' in S : [2, 21, 24, 27, 33, 35]

occur(S,'a',4th) == 27

occurence(S,'a',4th) == 27

2番目の解決策は複雑に見えますが、実際にはそうではありません。 iterableを完全に実行する必要はありません。必要なオカレンスが見つかるとすぐにプロセスが停止します。

2
eyquem
[y for y in enumerate(x) if y[1]==True][z][0]

注:ここで、Zはn番目のオカレンスです。

2
avasal

リストnthxitrblのオカレンスを見つける別の方法を次に示します。

def nthoccur(nth,x,itrbl):
    count,index = 0,0
    while count < nth:
        if index > len(itrbl) - 1:
            return None
        Elif itrbl[index] == x:
            count += 1
            index += 1
        else:
            index += 1
    return index - 1
2
apolune

これでうまくいくと思います。

def get_nth_occurrence_of_specific_term(my_list, term, n):
    assert type(n) is int and n > 0
    start = -1
    for i in range(n):
        if term not in my_list[start + 1:]:
            return -1
        start = my_list.index(term, start + 1)
    return start
0
Johnny Woo

count を使用できます:

_from itertools import count

x = [False, True, True, False, True, False, True, False, False, False, True, False, True]


def nth_index(n, item, iterable):
    counter = count(1)
    return next((i for i, e in enumerate(iterable) if e == item and next(counter) == n), -1)


print(nth_index(3, True, x))
_

出力

_4
_

アイデアは、e == item and next(counter) == n)の短絡特性により、式next(counter) == nは_e == item_の場合にのみ評価されるため、item

0
Dani Mesejo

ここに方法があります:
上記の例の場合:

x=[False,True,True,False,True,False,True,False,False,False,True,False,True]

関数find_indexを定義できます

def find_index(lst, value, n):
    c=[]
    i=0
    for element in lst :
          if element == value :
              c .append (i)
          i+=1    
    return c[n]

そして、関数を適用すると:

nth_index = find_index(x, True, 4)
print nth_index

結果は次のとおりです。

10
0
mzn.rft

nextenumerateおよびジェネレータ式を使用できます。 itertools.islice 必要に応じて、イテラブルをスライスできます。

from itertools import islice

x = [False,True,True,False,True,False,True,False,False,False,True,False,True]

def get_nth_index(L, val, n):
    """return index of nth instance where value in list equals val"""
    return next(islice((i for i, j in enumerate(L) if j == val), n-1, n), -1)

res = get_nth_index(x, True, 3)  # 4

イテレータが使い果たされた場合、つまり、指定された値のn番目のオカレンスが存在しない場合、nextはデフォルト値を返すことができます。この場合には -1

0
jpp