Bir listede maksimum değerin tüm konumlarını nasıl bulurum?


152

Bir listem var:

a = [32, 37, 28, 30, 37, 25, 27, 24, 35, 55, 23, 31, 55, 21, 40, 18, 50,
             35, 41, 49, 37, 19, 40, 41, 31]

max öğesi 55'tir (9 ve 12. konumda iki öğe)

Maksimum değerin hangi pozisyonda / konumlarda olduğunu bulmam gerekiyor. Lütfen yardım et.

Yanıtlar:


210
>>> m = max(a)
>>> [i for i, j in enumerate(a) if j == m]
[9, 12]

4
Listeden birden fazla geçiş yapmak sakıncası yoksa güzel kısa cevap - ki bu muhtemelen.
martineau

Bunun için büyük 0 2n dışında, liste bir kez maks'i belirlemek için 2x ve maks. Geçerli maksimum değeri ve konumunu izleyen bir for döngüsü, gerçekten uzun listeler için daha verimli olabilir.
radtek

1
@ radtek big O sadece n. önde gelen katsayılar büyük O göz ardı edilir
michaelsnowden

1
Teorik olarak O (N) ve O (2N) aynıdır, ancak pratikte O (N), özellikle N sonsuza yaklaştıkça kesinlikle daha kısa bir çalışma süresine sahip olacaktır.
radtek

314
a.index(max(a))

size listenin en büyük değerli öğesinin ilk örneğinin dizinini söyleyecektir a.


8
Bu sadece ilk örneği alır ve en büyük değerin bulunduğu tüm dizinleri sordu. Her durumda geri kalan listeyi almak ve artık bulunmadığında istisnayı işlemek için dilimi kullanarak bu döngüye girmeniz gerekir.
jaydel

10
Sadece ilk örneği vereceğinden bahsettim. Hepsini istiyorsanız, SilentGhost'un çözümü çok daha güzel ve daha az hataya yatkındır.
nmichaels

7
En azından ben geldiğimde, soru açıkça birden fazla maksimum durumunda bir liste istiyor ...
emmagras

2
Teknik olarak, bunu en büyük değerli öğenin ilk örneğini almak ve sonra gülünç derecede büyük bir negatif sayıya ayarlamak ve sonra bir sonraki en büyük değerli öğeyi bulmak için kullanabilirsiniz, ancak bu çok karmaşık olacaktır.
Neil Chowdhury

@nmichaels Bir listede maksimum değerin tüm konumlarını kabul edilen cevaptan almanın en iyi yolu var mı?
shaik moeed

18

Seçilen cevap (ve çoğu diğer) listeden en az iki geçiş gerektirir.
Daha uzun listeler için daha iyi bir seçim olabilecek tek geçişli bir çözüm.

Düzenlendi: @ John Machin tarafından belirtilen iki eksikliği gidermek için. (2) için her bir durumun ve seleflerin izin verdiği çıkarımların tahmin edilen olasılığını temel alarak testleri optimize etmeye çalıştım. Bunun için uygun başlatma değerlerini bulmaktan biraz zor oldu max_valve max_indicesmaksimum listedeki ilk değer olması oldu, özellikle eğer mümkünse durumlar için çalıştığı - ama artık biliyor inanıyoruz.

def maxelements(seq):
    ''' Return list of position(s) of largest element '''
    max_indices = []
    if seq:
        max_val = seq[0]
        for i,val in ((i,val) for i,val in enumerate(seq) if val >= max_val):
            if val == max_val:
                max_indices.append(i)
            else:
                max_val = val
                max_indices = [i]

    return max_indices

4
(1) Boş liste işleme dikkat gerektirir. []Reklamı yapılan gibi ("Dönüş listesi") dönmelidir . Kod basit olmalıdır if not seq: return []. (2) Döngüdeki test şeması alt optimaldir: ortalama olarak rastgele listelerde durum val < maxvalen yaygın olacaktır, ancak yukarıdaki kod bir yerine 2 test alır.
John Machin

John Machin'in doktrinle tutarsızlığı yakalamak ve en uygun olmayan kodları yayınlamama izin vermemek için yaptığı yorumdan +1. Dürüst olmak gerekirse, bir cevap zaten kabul edildiğinden, cevabım üzerinde çalışmaya devam etmek için biraz motivasyon kaybettim, çünkü daha fazla kimsenin buna bakmayacağını bile düşündüm - ve bu herkesinkinden çok daha uzun.
martineau

1
@martineau: "kabul edilmiş" cevaplar mutlaka "kabul edilebilir" değildir. Genel olarak tüm cevapları okurum. Düzeltmeniz dahil. Şimdi ==2 yerine nadir durumlarda 3 test yapar - elifdurumunuz her zaman doğru olacaktır.
John Machin

@John Machin: Gerçekten ilham aldım ve daha da revize ettim. Şimdi asgari ek testlerin yanı sıra birkaç değişiklik daha var. Yorumlarınız ve yapıcı eleştirileriniz için teşekkürler. elifKendimi her zaman Gerçek olarak yakaladım FWIW. ;-)
martineau

@John Machin: Hmmm, zamanlama sonuçlarınız kendimle çelişiyor gibi görünüyor, bu yüzden zamanlama hakkındaki cevabımda söylediğim şeyi kaldıracağım, böylece daha neler olup bittiğine bakabilirim. Söylediğin için teşekkürler. Aslında "gerçek" bir zamanlama testinin rastgele liste değerlerini kullanması gerektiğini düşünüyorum.
martineau

10

Ben aşağıda ile geldi ve bunu birlikte görebileceğiniz gibi çalışır max, minbu gibi listelerin üzerine fonksiyonları ve diğerleri:

Yani, konumunu öğrenmek Sonraki örnek listesini düşünün lütfen maksimum listesinde a:

>>> a = [3,2,1, 4,5]

Jeneratörü kullanma enumerateve döküm yapma

>>> list(enumerate(a))
[(0, 3), (1, 2), (2, 1), (3, 4), (4, 5)]

Bu noktada, pozisyonunu çıkarabilir max ile

>>> max(enumerate(a), key=(lambda x: x[1]))
(4, 5)

Yukarıda anlatılanlar, maksimum 4 pozisyonunda ve değeri 5'tir.

Gördüğünüz gibi, keyargümanda, uygun bir lambda tanımlayarak, yinelenebilir herhangi bir nesne üzerindeki maksimum değeri bulabilirsiniz.

Umarım katkıda bulunur.

PD: @PaulOyster'ın bir yorumda belirttiği gibi. İle ve yeni bir anahtar kelime izin zam istisna önlemek argüman boş liste olduğunda.Python 3.xminmaxdefaultValueErrormax(enumerate(list), key=(lambda x:x[1]), default = -1)


2
Bu daha iyi bir çözümdür, çünkü tek bir geçiş içerir. Ancak birkaç yorum: 1. numaralandırmayı listelemeye gerek yok (), 2. lambda daha iyi parantez içinde, 3. min () ve max () artık varsayılan bir parametreye sahip (boş girişte döndürülür), bu yüzden kullanabilirsiniz bir ValueError istisnasından kaçınmak için (örneğin, varsayılan = -1) ve 4. orijinal soru olduğu için lütfen max () olarak değiştirin.
Paul Oyster

yaklaşık 3 ürün, evet, sadece Python 3.x ile çalışır. Bundan bahsedeceğim. Ve diğer her şeyi düzeltti. ;)
jonaprieto

2
Bu, listede yalnızca bir kereden fazla meydana geldiğinde maksimum değerli öğelerden birinin (birincisi) konumunu bulur - bu nedenle sorulan soruya cevap vermez.
martineau

8

@Martineau tarafından alıntılanan @ SilentGhost dayak performansını çoğaltamıyorum. İşte karşılaştırma ile benim çaba:

=== maxelements.py ===

a = [32, 37, 28, 30, 37, 25, 27, 24, 35, 55, 23, 31, 55, 21, 40, 18, 50,
             35, 41, 49, 37, 19, 40, 41, 31]
b = range(10000)
c = range(10000 - 1, -1, -1)
d = b + c

def maxelements_s(seq): # @SilentGhost
    ''' Return list of position(s) of largest element '''
    m = max(seq)
    return [i for i, j in enumerate(seq) if j == m]

def maxelements_m(seq): # @martineau
    ''' Return list of position(s) of largest element '''
    max_indices = []
    if len(seq):
        max_val = seq[0]
        for i, val in ((i, val) for i, val in enumerate(seq) if val >= max_val):
            if val == max_val:
                max_indices.append(i)
            else:
                max_val = val
                max_indices = [i]
    return max_indices

def maxelements_j(seq): # @John Machin
    ''' Return list of position(s) of largest element '''
    if not seq: return []
    max_val = seq[0] if seq[0] >= seq[-1] else seq[-1]
    max_indices = []
    for i, val in enumerate(seq):
        if val < max_val: continue
        if val == max_val:
            max_indices.append(i)
        else:
            max_val = val
            max_indices = [i]
    return max_indices

Windows XP SP3'te Python 2.7 çalıştıran eski bir dizüstü bilgisayarın sonuçları:

>\python27\python -mtimeit -s"import maxelements as me" "me.maxelements_s(me.a)"
100000 loops, best of 3: 6.88 usec per loop

>\python27\python -mtimeit -s"import maxelements as me" "me.maxelements_m(me.a)"
100000 loops, best of 3: 11.1 usec per loop

>\python27\python -mtimeit -s"import maxelements as me" "me.maxelements_j(me.a)"
100000 loops, best of 3: 8.51 usec per loop

>\python27\python -mtimeit -s"import maxelements as me;a100=me.a*100" "me.maxelements_s(a100)"
1000 loops, best of 3: 535 usec per loop

>\python27\python -mtimeit -s"import maxelements as me;a100=me.a*100" "me.maxelements_m(a100)"
1000 loops, best of 3: 558 usec per loop

>\python27\python -mtimeit -s"import maxelements as me;a100=me.a*100" "me.maxelements_j(a100)"
1000 loops, best of 3: 489 usec per loop

7
a = [32, 37, 28, 30, 37, 25, 27, 24, 35, 
         55, 23, 31, 55, 21, 40, 18, 50,
         35, 41, 49, 37, 19, 40, 41, 31]

import pandas as pd

pd.Series(a).idxmax()

9

Ben genellikle böyle yaparım.


6

Numpy paketini de kullanabilirsiniz:

import numpy as np
A = np.array(a)
maximum_indices = np.where(A==max(a))

Bu, maks değerini içeren tüm dizinlerin sayısal bir dizisini döndürür

bunu bir listeye dönüştürmek istiyorsanız:

maximum_indices_list = maximum_indices.tolist()

5
>>> max(enumerate([1,2,3,32,1,5,7,9]),key=lambda x: x[1])
>>> (3, 32)

Bu yanlış. Maksimum sayıyı listenin ortasına koymaya çalışın.
goncalopp

1
Bu yanlış. Soru "maksimum değerin tüm pozisyonlarını bul" diyor.
Kapil

5

Ayrıca, sadece ilk görünümü veren bir çözüm, aşağıdakiler kullanılarak elde edilebilir numpy:

>>> import numpy as np
>>> a_np = np.array(a)
>>> np.argmax(a_np)
9

3

@shash bunu başka bir yerde yanıtladı

Maksimum liste öğesinin dizinini bulmanın Pythonic yolu

position = max(enumerate(a), key=lambda x: x[1])[0]

Hangisi geçer . Yine de, @Silent_Ghost ve daha da fazlası @nmichaels'ın çözümünden daha yavaştır:

for i in s m j n; do echo $i;  python -mtimeit -s"import maxelements as me" "me.maxelements_${i}(me.a)"; done
s
100000 loops, best of 3: 3.13 usec per loop
m
100000 loops, best of 3: 4.99 usec per loop
j
100000 loops, best of 3: 3.71 usec per loop
n
1000000 loops, best of 3: 1.31 usec per loop

2

İşte maksimum değeri ve göründüğü dizinler:

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> a = [32, 37, 28, 30, 37, 25, 27, 24, 35, 55, 23, 31, 55, 21, 40, 18, 50, 35, 41, 49, 37, 19, 40, 41, 31]
>>> for i, x in enumerate(a):
...     d[x].append(i)
... 
>>> k = max(d.keys())
>>> print k, d[k]
55 [9, 12]

Daha sonra: @SilentGhost'un memnuniyeti için

>>> from itertools import takewhile
>>> import heapq
>>> 
>>> def popper(heap):
...     while heap:
...         yield heapq.heappop(heap)
... 
>>> a = [32, 37, 28, 30, 37, 25, 27, 24, 35, 55, 23, 31, 55, 21, 40, 18, 50, 35, 41, 49, 37, 19, 40, 41, 31]
>>> h = [(-x, i) for i, x in enumerate(a)]
>>> heapq.heapify(h)
>>> 
>>> largest = heapq.heappop(h)
>>> indexes = [largest[1]] + [x[1] for x in takewhile(lambda large: large[0] == largest[0], popper(h))]
>>> print -largest[0], indexes
55 [9, 12]

bunun ne kadar verimsiz olduğunun farkında mısın?
SilentGhost

1
Rasyonalizasyonlar: (1) "Erken optimizasyon ... vb." (2) Muhtemelen önemli değil. (3) Hala iyi bir çözüm. Belki kullanmak için yeniden kodlayacağım heapq- maksimum değeri bulmak önemsiz olurdu.
hughdbrown

heapqçözümünüzü görmek isterken işe yarayacağından şüpheliyim.
SilentGhost

2

Bir liste kavrayışı ile ama numarasız benzer fikir

m = max(a)
[i for i in range(len(a)) if a[i] == m]

Ben downvoter değilim, ama bunun gerçekten hoş görünmediğine ve iyi performans göstermeyeceğine dikkat edin: liste yerine endeksleri tekrarlamak Python'da çok garip, bundan kaçınmaya çalışıyorsunuz. Ayrıca, a[i]çağrı nedeniyle numaralandırma ile çözümden kesinlikle daha yavaş .
'

1

Sadece bir satır:

idx = max(range(len(a)), key = lambda i: a[i])

Güzel, ama TÜM dizinleri döndürmez, sadece birincisi.
Iggy

1

Listelenen nbir listede en büyük sayıların indekslerini almak dataistiyorsanız, Pandaları kullanabilirsiniz sort_values:

pd.Series(data).sort_values(ascending=False).index[0:n]

0
import operator

def max_positions(iterable, key=None, reverse=False):
  if key is None:
    def key(x):
      return x
  if reverse:
    better = operator.lt
  else:
    better = operator.gt

  it = enumerate(iterable)
  for pos, item in it:
    break
  else:
    raise ValueError("max_positions: empty iterable")
    # note this is the same exception type raised by max([])
  cur_max = key(item)
  cur_pos = [pos]

  for pos, item in it:
    k = key(item)
    if better(k, cur_max):
      cur_max = k
      cur_pos = [pos]
    elif k == cur_max:
      cur_pos.append(pos)

  return cur_max, cur_pos

def min_positions(iterable, key=None, reverse=False):
  return max_positions(iterable, key, not reverse)

>>> L = range(10) * 2
>>> L
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> max_positions(L)
(9, [9, 19])
>>> min_positions(L)
(0, [0, 10])
>>> max_positions(L, key=lambda x: x // 2, reverse=True)
(0, [0, 1, 10, 11])

0

Bu kod, daha önce gönderilen cevaplar kadar karmaşık değildir, ancak çalışır:

m = max(a)
n = 0    # frequency of max (a)
for number in a :
    if number == m :
        n = n + 1
ilist = [None] * n  # a list containing index values of maximum number in list a.
ilistindex = 0
aindex = 0  # required index value.    
for number in a :
    if number == m :
        ilist[ilistindex] = aindex
        ilistindex = ilistindex + 1
    aindex = aindex + 1

print ilist

Yukarıdaki koddaki ilist , listede maksimum sayının tüm konumlarını içerecektir.


0

Bunu çeşitli şekillerde yapabilirsiniz.

Eski geleneksel yol,

maxIndexList = list() #this list will store indices of maximum values
maximumValue = max(a) #get maximum value of the list
length = len(a)       #calculate length of the array

for i in range(length): #loop through 0 to length-1 (because, 0 based indexing)
    if a[i]==maximumValue: #if any value of list a is equal to maximum value then store its index to maxIndexList
        maxIndexList.append(i)

print(maxIndexList) #finally print the list

Listenin uzunluğunu hesaplamadan ve herhangi bir değişkene maksimum değer kaydetmeden başka bir yol,

maxIndexList = list()
index = 0 #variable to store index
for i in a: #iterate through the list (actually iterating through the value of list, not index )
    if i==max(a): #max(a) returns a maximum value of list.
        maxIndexList.append(index) #store the index of maximum value
index = index+1 #increment the index

print(maxIndexList)

Pythonic ve akıllı bir şekilde yapabiliriz! Liste kavrayışı sadece bir satırda kullanmak,

maxIndexList = [i for i,j in enumerate(a) if j==max(a)] #here,i=index and j = value of that index

Tüm kodlarım Python 3'te.

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.