Listede max () / min () kullanarak döndürülen max veya min öğesinin dizinini alma


467

Bir minimax algoritması için listelerde Python'ın maxve minişlevlerini kullanıyorum ve max()veya tarafından döndürülen değerin dizinini gerekiyor min(). Başka bir deyişle, hangi hamlenin max (ilk oyuncunun dönüşünde) veya min (ikinci oyuncu) değerini ürettiğini bilmem gerekir.

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)

Sadece değeri değil, min veya maks değeri gerçek dizin döndürmek gerekir.


32
Yerleşik çok şey divmodsöylemek zorunda kalmamak için var [i / 3, i % 3].
Mike Graham

Yanıtlar:


417
isMinLevel ise:
    return value.index (min (değerler))
Başka:
    return value.index (maks. (değerler))

38
@KevinGriffin, bunun size minimum / maksimumun birkaç tekrarından sadece birini getirdiğini unutmayın. İstediğiniz şey bu olmayabilir, örneğin kazancınızı aynı iki şekilde artırmak mümkünse, ancak bunlardan biri diğer oyuncuya daha fazla zarar verir. Bunun göz önünde bulundurmanız gereken bir durum olup olmadığını bilmiyorum.
Mike Graham

89
@Kashyap Aslında O (N), O (N ^ 2) değil. Min durumunda, O (N) olan ilk min (değerler) değerlendirilir, ardından O (N) olan değerler.index () çağrılır. O (N) + O (N) = 0 (N). Endeksleme argümanı sadece bir kez değerlendirilir. Eşdeğer:tmp = min(values); return values.index(tmp)
Tom Karzes

@ çok php elementlerin tekrarı olduğunda ne yapmalı?
Shashi Tunga

@ShashiTunga [list] .index () yalnızca bir şeyin ilk ortaya çıkışını döndürür, özel olduğu garanti edilmez, minimum değer listede benzersiz olmayabilir
Scott Anderson

473

Bir listeniz olduğunu values = [3,6,1,5]ve en küçük öğenin dizinine ihtiyacınız olduğunu varsayalım.index_min = 2 bu durumda .

itemgetter()Diğer cevaplarda sunulan çözümden kaçının ve bunun yerine kullanın

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

çünkü import operatorkullanması veya kullanması gerekmiyor enumerateve her zaman kullanılan bir çözümden daha hızlı (aşağıda kıyaslama)itemgetter() .

Numpy dizilerle uğraşıyorsanız veya numpybağımlılık olarak para ödeyebiliyorsanız ,

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

Bu, aşağıdaki durumlarda saf bir Python listesine uygulasanız bile ilk çözümden daha hızlı olacaktır:

  • birkaç elemandan daha büyük (makinemdeki yaklaşık 2 ** 4 eleman)
  • salt listeden bir numpydiziye bellek kopyasını alabilirsiniz

Bu temel ölçütün belirttiği gibi: resim açıklamasını buraya girin

Yukarıdaki iki çözüm (mavi: saf python, ilk çözüm) (kırmızı, numpy çözüm) ve itemgetter()(siyah, referans çözüm) tabanlı standart çözüm için makinemde python 2.7 ile karşılaştırmayı yaptım . Python 3.5 ile aynı kriter, yöntemlerin yukarıda sunulan python 2.7 vakası ile tam olarak aynı olduğunu gösterdi


Çok güçlü bir +1. Önerilen çözümlerin karşılaştırmasını ve özetlediğiniz temel kuralları seviyorum. Aşağıdaki başka bir cevapta önerdiğim gibi, test kodunuzu başkalarının sonuçlarınızı yeniden üretebilmesi için sağlayabilir misiniz (veya bağlantı verebilir misiniz)? Makineler ve kütüphaneler zamanla değişir ve diğer çözümlerle karşılaştırmaya izin verir.
Rakurai

3
Bence bir yazım hatası olabilir: xrange. Menzil olmamalı mı?
Lindsay Fowler

6
@LindsayFowler xrange()artık kullanımdan kaldırıldı, kullanabilirsinizrange()
davide

np.argmin şamandıralar için çalışmaz. sadece ilk öneri ints ve şamandıralar üzerinde çalışır.
jimh

Bence yanılıyorsun, dene import numpy as np; x = [2.3, -1.4]; np.argmin(x). argminŞamandıralarda da işe yaradığını göreceksiniz
gg349

332

Listedeki öğeleri numaralandırırsanız min / max dizinini ve değerini aynı anda bulabilirsiniz, ancak listenin orijinal değerlerinde min / max gerçekleştirin. Şöyle ki:

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

Bu şekilde liste en az (veya en fazla) süreyle yalnızca bir kez geçer.


110
: Ya da bir lambda kullanmakkey=lambda p: p[1]
scry

116

(Dizin durumunuz gibi görünüyor) bir sayı listesi içinde max dizinini bulmak istiyorsanız, o zaman numpy kullanmanızı öneririz:

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

Maksimum değerlerin birden çok tekrarlanması durumunda, ilk tekrarlamaya karşılık gelen indeksler döndürülür.
Cohensius

41

Muhtemelen daha basit bir çözüm, değer dizisini bir değer dizisine, dizin çiftlerine dönüştürmek ve bunun maksimum / dakikasını almak olabilir. Bu, max / min değerine sahip en büyük / en küçük indeksi verecektir (yani, çiftler ilk önce birinci eleman karşılaştırılarak ve daha sonra ilk elemanlar aynıysa ikinci eleman karşılaştırılarak). Dizinin gerçekten oluşturulması gerekmediğine dikkat edin, çünkü min / max üreteçlere girdi olarak izin verir.

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

Size minimumun ilk dizinini verecektir.


18

Yapılacak en iyi şey listeyi bir dönüştürmek numpy arrayve bu işlevi kullanmak olduğunu düşünüyorum :

a = np.array(list)
idx = np.argmax(a)

14

Ben de bununla ilgilendim ve perfplot (benim bir evcil hayvan projesi) kullanarak önerilen çözümlerin bazılarını karşılaştırdım .

O numpy'nin argmin'i ortaya çıkıyor ,

numpy.argmin(x)

Hatta girişinden örtülü dönüşüm ile, yeterince büyük bir listesi için hızlı bir yöntem olup lista numpy.array.

resim açıklamasını buraya girin


Arsa oluşturmak için kod:

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

Aynı sonucun, 2 yıldan fazla bir süre önce cevabımda, argmin'in ne zaman ve neden kullanılacağı veya kullanılamayacağı hakkında daha fazla bilgi ile birlikte yayınlandığına dikkat edin. Aynı sayfada daha önce teklif edilenlere de fayda sağlamayan yanıtı silmeyi düşünün. Benzer davranış için SO'daki diğer cevaplarınızı da gözden geçirmeyi düşünün: performans analizlerinizde en iyi çözümü sunan gerçek cevabı belirtmiyor gibi görünüyorsunuz. Bu, özellikle daha iyi bilmek için yeterince uzun olan> 10K temsilcisi olan biri için oldukça kötüdür.
gg349

@ gg349, çok iyi puanlar, ancak sonuçları üretmek için kaynak kodunu sağlayarak bunu kolayca yeniden üretilebilir ve diğer çözümleri karşılaştırmaya uyarlanabilir hale getirir. Bu cevabı bir kopya olarak kaldırmayı düşünebileceğini kabul ediyorum, ancak belki de kullandığınız kodu ekleyerek veya ona bağlayarak cevabınıza değer katabilirsiniz?
Rakurai

8

Bir numpy dizisi ve argmax () işlevi kullanın

 a=np.array([1,2,3])
 b=np.argmax(a)
 print(b) #2

8

Maksimum değerleri aldıktan sonra şunu deneyin:

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

Birçok seçenekten çok daha basit.


6

Yukarıdaki cevabın sorununuzu çözdüğünü düşünüyorum, ancak size minimum ve minimum görünen tüm endeksleri veren bir yöntemi paylaşacağımı düşündüm.

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

Bu listeyi iki kez geçer, ancak yine de oldukça hızlıdır. Bununla birlikte, asgari ilk karşılaşma endeksini bulmaktan biraz daha yavaştır. Yani minimallerin sadece birine ihtiyacınız varsa, Matt Anderson'ın çözümünü kullanın, hepsine ihtiyacınız varsa bunu kullanın.


1
O baz Python kullanır ve ben daha kolay liste anlama itemgetter daha anlamak için bulmak çünkü bu gibi lambda vb (ve esnek yeterince .... Bu gibi görevler, çeşitli çözmek için)
James

çiğ. Bunu tercih ederim.
Dev_Man

6

Numpy modülünün işlevini kullanın numpy.where

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

Minimum değerin dizini için:

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

Maksimum değerin dizini için:

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

Aslında, bu işlev çok daha güçlüdür. 3 ile 60 arasındaki değer dizini için her türlü boole işlemini yapabilirsiniz:

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

python içindeki dizin 0'dan başlar. Döndürülen dizin 6 (65 için) olurken, kodunuz 7 döndürür (OP'nin sorusu "Dizini alma ...")
tagoma

Komutta, dizini IS 7. 65 olan dizideki öğelerin maksimum değeri olan minimum değer dizini (burada: 1) için sorguladım. N.where (x == x.max ()) [0] yazarsanız, maks. Burada 65 olan değer. Endeks 6
İşhan Tomar

numpy kullanımı: muhtemelen bu uygulamada yasaklanmıştır. Ancak numpy kullanacaksanız, argmin()burada yaptığınız şey yerine kullanmaktan çok daha iyi olursunuz.
RBF06

Teşekkürler @ RBF06 Kontrol edeceğim.
İşhan Tomar

5

Bu, yerleşik enumerate()ve max()işlev ve isteğe bağlı olarak kolayca mümkündürkey argümanı max()ve basit bir lambda ifadesi kullanılarak mümkündür:

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

Bunun için dokümanlarda max(), keyargümanın,list.sort() . Ayrıca Sıralama Nasıl Yapılır konusuna bakın .

Aynı şekilde çalışır min(). Btw ilk maks / min değerini döndürür.


Geç ama en iyi cevap (hıza ihtiyacınız yoksa).
mmj

5

Şöyle bir listeniz olduğunu varsayalım:

a = [9,8,7]

Aşağıdaki iki yöntem, minimum öğe ve dizini ile bir demet almak için oldukça kompakt yollardır. Her ikisinin de işlenmesi benzer bir zaman alır . Zip yöntemini beğendim, ama bu benim zevkim.

zip yöntemi

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)

numaralandırma yöntemi

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

Lambda ve "anahtar" argümanını nasıl kullanacağınızı bildiğiniz sürece, basit bir çözüm:

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

Çok temiz! Ve kabul edilen cevabın aksine, bu doğru O (n), değil mi? O (2n) 'nin O (n) olarak kabul edildiğini biliyorum, ama çok büyük niçin fark edilir derecede daha yavaş olabilir.
kevlarr

4

Bu kadar basit :

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

index = stuff.index(max(stuff))

3

Neden önce endeks eklemek ve sonra tersine çevirmek için uğraşasınız ki? Enumerate () işlevi, zip () işlevi kullanımının özel bir örneğidir. Bunu uygun bir şekilde kullanalım:

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

Daha önce söylenenlere sadece küçük bir katkı. values.index(min(values))min. Aşağıdaki en büyük endeksi alır:

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

Yerinde geri gitmenin yan etkisi önemli değilse, son satır dışarıda bırakılabilir.

Tüm tekrarları yinelemek

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

Kısalık uğruna. min(values), values.count(min)Döngünün dışında önbelleklemek muhtemelen daha iyi bir fikirdir .


2
reversed(…)bunun yerine ….reverse()büyük olasılıkla tercih edilmez, çünkü zaten bir jeneratörü değiştirmez ve döndürür. Ve tüm olaylar da olabilirminv = min(values); indices = [i for i, v in enumerate(values) if v == minv]
HoverHell

2

Ek modülleri içe aktarmak istemiyorsanız, listede minimum değere sahip dizinleri bulmanın basit bir yolu:

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

Sonra ilkini seçin:

choosen = indexes_with_min_value[0]


0

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

Birden fazla öğe maksimumsa, işlev karşılaşılan ilk öğeyi döndürür. Bu, aşağıdakiler gibi diğer sıralama kararlılığı koruma araçlarıyla tutarlıdır.sorted(iterable, key=keyfunc, reverse=True)[0]

Sadece ilk yöntemden daha fazlasını elde etmek için sıralama yöntemini kullanın.

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

Peki buna ne dersin:

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

aAnahtarlar içindeki öğelerden ve dizinleri değer olarak bir sözlük oluşturur , böylece dict(zip(a,range(len(a))))[max(a)]a'daki max(a)maksimumun dizini olan anahtara karşılık gelen değeri döndürür . Python'da yeni başlayan biriyim, bu yüzden bu çözümün hesaplama karmaşıklığını bilmiyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.