web-dev-qa-db-ja.com

Python=のリストで一致する要素のインデックスを見つける

「平均」と呼ばれる、1から5の範囲の浮動小数点数の長いリストがあり、aより小さいまたはbより大きい要素のインデックスのリストを返したい

def find(lst,a,b):
    result = []
    for x in lst:
        if x<a or x>b:
            i = lst.index(x)
            result.append(i)
    return result

matches = find(average,2,4)

しかし、驚くべきことに、「一致」の出力には多くの繰り返しがあります。 [2, 2, 10, 2, 2, 2, 19, 2, 10, 2, 2, 42, 2, 2, 10, 2, 2, 2, 10, 2, 2, ...]

なぜこうなった?

27
Logan Yang

リストで値の(firstオカレンスのみを検索する.index()を使用しています。したがって、インデックス2とインデックス9に値1.0がある場合、.index(1.0)は何度でもalwaysが_2_を返します_1.0_はリストにあります。

代わりに enumerate() を使用して、ループにインデックスを追加します。

_def find(lst, a, b):
    result = []
    for i, x in enumerate(lst):
        if x<a or x>b:
            result.append(i)
    return result
_

これをリスト内包表記にまとめることができます:

_def find(lst, a, b):
    return [i for i, x in enumerate(lst) if x<a or x>b]
_
55
Martijn Pieters

これはかなり重い依存関係ですが、この種のことをたくさんしている場合は、numpyの使用を検討してください。

In [56]: import random, numpy

In [57]: lst = numpy.array([random.uniform(0, 5) for _ in xrange(1000)]) # example list

In [58]: a, b = 1, 3

In [59]: numpy.flatnonzero((lst > a) & (lst < b))[:10]
Out[59]: array([ 0, 12, 13, 15, 18, 19, 23, 24, 26, 29])

Seanny123の質問に答えて、次のタイミングコードを使用しました。

import numpy, timeit, random

a, b = 1, 3

lst = numpy.array([random.uniform(0, 5) for _ in xrange(1000)])

def numpy_way():
    numpy.flatnonzero((lst > 1) & (lst < 3))[:10]

def list_comprehension():
    [e for e in lst if 1 < e < 3][:10]

print timeit.timeit(numpy_way)
print timeit.timeit(list_comprehension)

Numpyバージョンは60倍以上高速です。

2
Alex Coventry