リストでmax()/ min()を使用して、返された最大または最小アイテムのインデックスを取得する


465

ミニマックスアルゴリズムのリストでPythonの関数maxmin関数を使用していて、max()またはによって返される値のインデックスが必要min()です。言い換えれば、どの動きが最大(最初のプレーヤーのターンで)または最小(2番目のプレーヤー)の値を生み出したかを知る必要があります。

for i in range(9):
    newBoard = currentBoard.newBoardWithMove([i / 3, i % 3], player)

    if newBoard:
        temp = minMax(newBoard, depth + 1, not isMinLevel)  
        values.append(temp)

if isMinLevel:
    return min(values)
else:
    return max(values)

値だけでなく、最小値または最大値の実際のインデックスを返すことができる必要があります。


32
ビルトインdivmodは、[i / 3, i % 3]多くのことを言わなくても済むように存在しています。
マイクグラハム

回答:


416
isMinLevelの場合:
    戻り値.index(min(values))
そうしないと:
    戻り値.index(max(values))

38
@KevinGriffin、これにより、最小/最大の複数の発生のうちの1つだけが取得されることに注意してください。これはあなたが望むものではないかもしれません。たとえば、同じ2つの方法でゲインを増やすことが可能であるが、そのうちの1つが他のプレイヤーをさらに傷つける場合などです。これがあなたが考慮しなければならないケースであるかどうかはわかりません。
マイクグラハム、

89
@Kashyap実際にはO(N ^ 2)ではなくO(N)です。minの場合、最初にO(N)であるmin(values)が評価され、次にO.Nでもあるvalues.index()が呼び出されます。O(N)+ O(N)= O(N)。indexへの引数は一度だけ評価されます。それはと同等です:tmp = min(values); return values.index(tmp)
トムKarzes

要素の繰り返しがあるときに何をすべきかphpが多すぎますか?
Shashi Tunga

@ShashiTunga [リスト] .index()は、最初に出現したものだけを返します。これが排他的であるとは限りません。最小値がリスト内で一意でない可能性があります
スコットアンダーソン

473

リストvalues = [3,6,1,5]があり、最小の要素のインデックスが必要であるとしましょうindex_min = 2

itemgetter()他の回答で提示されている解決策を避け、代わりに使用してください

index_min = min(range(len(values)), key=values.__getitem__)

import operatorを使用する必要も、使用する必要もないため、を使用enumerateするソリューションよりも常に高速です(以下のベンチマーク)itemgetter()

numpy配列を処理している場合、またはnumpy依存関係として余裕がある場合は、次の使用も検討してください。

import numpy as np
index_min = np.argmin(values)

これは、次の場合に純粋なPythonリストに適用しても、最初のソリューションよりも高速になります。

  • いくつかの要素よりも大きい(私のマシンでは約2 ** 4要素)
  • 純粋なリストからnumpy配列へのメモリのコピーを買う余裕がある

このベンチマークが指摘するように: ここに画像の説明を入力してください

上記の2つのソリューション(青:純粋なpython、最初のソリューション)(赤、numpyソリューション)およびitemgetter()(黒、参照ソリューション)に基づく標準ソリューションのpython 2.7を使用してマシンでベンチマークを実行しました。Python 3.5と同じベンチマークは、メソッドが上記のPython 2.7のケースとまったく同じであることを示しました


非常に強い+1。提案されたソリューションのベンチマークと、要約した経験則が気に入っています。以下の別の回答で提案したように、他の人が結果を再現できるように、テストコードを提供(またはリンク)できますか?マシンとライブラリは時間とともに変化し、他のソリューションと比較できるようになります。
らくらい

3
タイプミスがあると思います:xrange。それは範囲ではありませんか?
Lindsay Fowler

6
@LindsayFowler xrange()は非推奨になりました。使用できますrange()
davide

np.argminは浮動小数点数では機能しません。最初の提案だけがintとfloatで機能します。
jimh

私はあなたが間違っていると思います、試してくださいimport numpy as np; x = [2.3, -1.4]; np.argmin(x)argminフロートでも機能することがわかります
gg349

332

リスト内のアイテムを列挙すると、最小/最大インデックスと値を同時に見つけることができますが、リストの元の値に対して最小/最大を実行します。そのようです:

import operator
min_index, min_value = min(enumerate(values), key=operator.itemgetter(1))
max_index, max_value = max(enumerate(values), key=operator.itemgetter(1))

この方法では、リストは最小(または最大)で1回だけトラバースされます。


110
:またはラムダ使用key=lambda p: p[1]
占術

116

数値のリスト内でmaxのインデックスを検索する場合(これはあなたのケースのようです)、numpyを使用することをお勧めします。

import numpy as np
ind = np.argmax(mylist)

最大値が複数出現する場合、最初の出現に対応するインデックスが返されます。
Cohensius

41

おそらく、より簡単な解決策は、値の配列を値の配列、インデックスのペアに変換し、その最大値/最小値を取得することです。これにより、最大値/最小値を持つ最大/最小のインデックスが得られます(つまり、最初の要素を最初に比較し、次に最初の要素が同じである場合は2番目の要素を比較することによってペアが比較されます)。min / maxはジェネレーターを入力として許可するため、実際に配列を作成する必要はないことに注意してください。

values = [3,4,5]
(m,i) = max((v,i) for i,v in enumerate(values))
print (m,i) #(5, 2)

30
list=[1.1412, 4.3453, 5.8709, 0.1314]
list.index(min(list))

最小の最初のインデックスを提供します。



14

私もこれに興味があり、perfplotを使用して提案されたソリューションのいくつかを比較しました(私のペットプロジェクト)。

そのnumpyのargminが判明し

numpy.argmin(x)

入力listからへの暗黙的な変換を行う場合でも、十分に大きいリストの場合は最速の方法ですnumpy.array

ここに画像の説明を入力してください


プロットを生成するためのコード:

import numpy
import operator
import perfplot


def min_enumerate(a):
    return min(enumerate(a), key=lambda x: x[1])[0]


def min_enumerate_itemgetter(a):
    min_index, min_value = min(enumerate(a), key=operator.itemgetter(1))
    return min_index


def getitem(a):
    return min(range(len(a)), key=a.__getitem__)


def np_argmin(a):
    return numpy.argmin(a)


perfplot.show(
    setup=lambda n: numpy.random.rand(n).tolist(),
    kernels=[
        min_enumerate,
        min_enumerate_itemgetter,
        getitem,
        np_argmin,
        ],
    n_range=[2**k for k in range(15)],
    logx=True,
    logy=True,
    )

同じ結論が2年以上前の私の回答の中ですでに投稿されており、argminをいつ使用できるか、なぜ使用できるかについての詳細情報が記載されています。回答を削除することを検討してください。これは、この同じページですでに提案されているものにメリットを与えていません。SOに関する他の回答も同様の動作について確認することを検討してください。パフォーマンス分析で最良のソリューションを提供する実際の回答を引用していないようです。これはかなり悪いことです。特に、10Kを超える担当者が十分に長く知っているため、十分に理解している場合はなおさらです。
gg349

@ gg349、非常に良い点ですが、彼は結果を生成するためのソースコードを提供しているため、これを簡単に再現し、他のソリューションと比較することができます。私は彼がこの回答を重複として削除することを検討するかもしれないことに同意しますが、おそらくあなたが使用したコードを含めるかリンクすることによってあなたの回答に価値を加えることができますか?
らくらい


8

最大値を取得したら、これを試してください:

max_val = max(list)
index_max = list.index(max_val)

多くのオプションよりもはるかに簡単です。


6

上記の答えはあなたの問題を解決すると思いますが、私はあなたに最小値と最小値が現れるすべてのインデックスを与える方法を共有したいと思いました。

minval = min(mylist)
ind = [i for i, v in enumerate(mylist) if v == minval]

これはリストを2回渡しますが、それでもかなり高速です。ただし、最小値の最初の出会いのインデックスを見つけるよりも少し遅くなります。したがって、最小値の1つだけが必要な場合はMatt Andersonのソリューションを使用し、すべてが必要な場合はこれを使用してください。


1
私、このことはベースのPythonを使用し、私はitemgetterより理解するために、リスト内包表記を簡単に見つけるため、ラムダなど(およびこのようなタスク、さまざまなを解決するために柔軟に十分な....)のような
ジェームズ・

生。私はこれが好きです。
Dev_Man

6

numpyモジュールの関数numpy.whereを使用する

import numpy as n
x = n.array((3,3,4,7,4,56,65,1))

最小値のインデックスの場合:

idx = n.where(x==x.min())[0]

最大値のインデックスの場合:

idx = n.where(x==x.max())[0]

実際、この機能ははるかに強力です。3〜60の値のインデックスの場合、あらゆる種類のブール演算をポーズできます。

idx = n.where((x>3)&(x<60))[0]
idx
array([2, 3, 4, 5])
x[idx]
array([ 4,  7,  4, 56])

Pythonのインデックスは0から始まります。返されるインデックスは6(65の場合)ですが、コードは7を返します(OPの質問は「インデックスの取得...」
でした

コマンドで、最小値(ここでは1)のインデックスを照会しました。そのインデックスは7です。65は配列内の要素の最大値です。次のように入力すると、n.where(x == x.max())[0]は最大のインデックスを取得します。ここでは65の値です。そのインデックスは6であることが判明します
Ishan Tomar

numpyの使用:このアプリケーションではおそらく禁止されています。しかし、numpyを使用するargmin()場合は、ここで行ったことの代わりに使用するだけの方がはるかに優れています。
RBF06

ありがとう@ RBF06私はそれをチェックします。
Ishan Tomar

5

これは、使用して簡単に可能であるビルトインenumerate()およびmax()機能とオプションkeyの引数max()機能と簡単なラムダ式:

theList = [1, 5, 10]
maxIndex, maxValue = max(enumerate(theList), key=lambda v: v[1])
# => (2, 10)

のドキュメントmax()では、key引数は関数のように関数を期待していると述べていますlist.sort()並べ替えの方法もご覧ください

でも同じように機能しmin()ます。ところで、最初の最大/最小値を返します。


遅くても最良の答え(速度が必要ない場合)。
mmj 2017

5

次のようなリストがあるとします。

a = [9,8,7]

次の2つのメソッドは、最小の要素とそのインデックスを持つタプルを取得するためのかなりコンパクトな方法です。どちらも処理に同じような時間がかかります。私はzipメソッドの方が好きですが、それが私の好みです。

zipメソッド

element, index = min(list(zip(a, range(len(a)))))

min(list(zip(a, range(len(a)))))
(7, 2)

timeit min(list(zip(a, range(len(a)))))
1.36 µs ± 107 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

列挙メソッド

index, element = min(list(enumerate(a)), key=lambda x:x[1])

min(list(enumerate(a)), key=lambda x:x[1])
(2, 7)

timeit min(list(enumerate(a)), key=lambda x:x[1])
1.45 µs ± 78.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

4

ラムダと「キー」引数の使い方を知っている限り、簡単な解決策は次のとおりです。

max_index = max( range( len(my_list) ), key = lambda index : my_list[ index ] )

非常にきれいな!そして、受け入れられた答えとは異なり、これは本当の O(n)ですよね?O(2n)はO(n)と見なされますが、非常に大きいn場合は著しく遅くなることがあります。
kevlarr 2017

4

そのような単純な :

stuff = [2, 4, 8, 15, 11]

index = stuff.index(max(stuff))

3

インデックスを最初に追加してから逆順にするのはなぜですか?Enumerate()関数は、zip()関数の使用法の特殊なケースです。それを適切な方法で使用しましょう:

my_indexed_list = zip(my_list, range(len(my_list)))

min_value, min_index = min(my_indexed_list)
max_value, max_index = max(my_indexed_list)

2

すでに述べられていることへのほんの少しの追加。 values.index(min(values))最小のインデックスを返すようです。以下は最大のインデックスを取得します:

    values.reverse()
    (values.index(min(values)) + len(values) - 1) % len(values)
    values.reverse()

逆転の副作用が問題にならない場合は、最後の行を省略できます。

すべての発生を繰り返す

    indices = []
    i = -1
    for _ in range(values.count(min(values))):
      i = values[i + 1:].index(min(values)) + i + 1
      indices.append(i)

簡潔にするために。min(values), values.count(min)ループの外側でキャッシュする方が良いでしょう。


2
reversed(…)代わりに….reverse()、それは変異せず、とにかくジェネレータを返すので、おそらく好ましいです。そして、すべての出来事はまた可能性がありますminv = min(values); indices = [i for i, v in enumerate(values) if v == minv]
HoverHell

2

追加のモジュールをインポートしたくない場合に、リストで最小値のインデックスを見つける簡単な方法:

min_value = min(values)
indexes_with_min_value = [i for i in range(0,len(values)) if values[i] == min_value]

次に、たとえば最初のものを選択します。

choosen = indexes_with_min_value[0]

1

既存の回答にコメントするのに十分な担当者がいない。

しかし、https://stackoverflow.com/a/11825864/3920439回答の場合

これは整数では機能しますが、浮動小数点数の配列では機能しません(少なくともpython 3.6では)。 TypeError: list indices must be integers or slices, not float


0

https://docs.python.org/3/library/functions.html#max

複数のアイテムが最大の場合、関数は最初に見つかったアイテムを返します。これは、次のようなソート安定性保持ツールと一致していますsorted(iterable, key=keyfunc, reverse=True)[0]

最初のもの以上のものを取得するには、sortメソッドを使用します。

import operator

x = [2, 5, 7, 4, 8, 2, 6, 1, 7, 1, 8, 3, 4, 9, 3, 6, 5, 0, 9, 0]

min = False
max = True

min_val_index = sorted( list(zip(x, range(len(x)))), key = operator.itemgetter(0), reverse = min )

max_val_index = sorted( list(zip(x, range(len(x)))), key = operator.itemgetter(0), reverse = max )


min_val_index[0]
>(0, 17)

max_val_index[0]
>(9, 13)

import ittertools

max_val = max_val_index[0][0]

maxes = [n for n in itertools.takewhile(lambda x: x[0] == max_val, max_val_index)]

0

これはどうですか:

a=[1,55,2,36,35,34,98,0]
max_index=dict(zip(a,range(len(a))))[max(a)]

これは、aキーとしての項目と値としてのインデックスから辞書を作成dict(zip(a,range(len(a))))[max(a)]するため、max(a)aの最大値のインデックスであるキーに対応する値を返します。私はPythonの初心者なので、このソリューションの計算の複雑さについてはわかりません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.