Lấy chỉ mục của mục tối đa hoặc tối thiểu được trả về bằng max () / min () trong danh sách


465

Tôi đang sử dụng Python maxvà các minhàm trong danh sách cho thuật toán minimax và tôi cần chỉ mục của giá trị được trả về bởi max()hoặc min(). Nói cách khác, tôi cần biết di chuyển nào tạo ra giá trị tối đa (ở lượt của người chơi thứ nhất) hoặc giá trị tối thiểu (người chơi thứ hai).

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)

Tôi cần có thể trả về chỉ số thực tế của giá trị tối thiểu hoặc tối đa, không chỉ giá trị.


32
Nội dung divmodtồn tại để ngăn chặn việc phải nói [i / 3, i % 3]nhiều.
Mike Graham

Câu trả lời:


416
nếu làMinLevel:
    trả về giá trị.index (min (giá trị))
khác:
    trả về giá trị.index (max (giá trị))

38
@KevinGriffin, Lưu ý rằng điều này chỉ mang lại cho bạn một trong số những lần xuất hiện tối thiểu / tối đa. Đây có thể không phải là điều bạn muốn, ví dụ nếu có thể tăng mức tăng của bạn theo hai cách tương tự, nhưng một trong số đó làm tổn thương người chơi khác nhiều hơn. Tôi không biết đây có phải là trường hợp bạn cần xem xét không.
Mike Graham

89
@Kashyap Đó thực sự là O (N), không phải O (N ^ 2). Trong trường hợp tối thiểu, min (giá trị) đầu tiên được ước tính, đó là O (N), sau đó giá trị.index () được gọi, cũng là O (N). O (N) + O (N) = O (N). Đối số để chỉ mục chỉ được đánh giá một lần. Nó tương đương với:tmp = min(values); return values.index(tmp)
Tom Karze

@too nhiều php phải làm gì khi có sự lặp lại của các yếu tố.?
Shashi Tunga

@ShashiTunga [list] .index () chỉ trả về lần xuất hiện đầu tiên của một thứ gì đó, không đảm bảo rằng nó là độc quyền, giá trị tối thiểu có thể không phải là duy nhất trong danh sách
Scott Anderson

472

Giả sử bạn có một danh sách values = [3,6,1,5]và cần chỉ mục của phần tử nhỏ nhất, tức là index_min = 2trong trường hợp này.

Tránh các giải pháp itemgetter()được trình bày trong các câu trả lời khác, và sử dụng thay thế

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

bởi vì nó không yêu cầu import operatorcũng không sử dụng enumeratevà nó luôn nhanh hơn (điểm chuẩn bên dưới) so với giải pháp sử dụng itemgetter().

Nếu bạn đang xử lý các mảng numpy hoặc có thể đủ khả năng numpynhư một phụ thuộc, hãy xem xét sử dụng

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

Điều này sẽ nhanh hơn giải pháp đầu tiên ngay cả khi bạn áp dụng nó vào danh sách Python thuần túy nếu:

  • nó lớn hơn một vài yếu tố (khoảng 2 ** 4 yếu tố trên máy của tôi)
  • bạn có thể đủ khả năng sao chép bộ nhớ từ một danh sách thuần túy sang một numpymảng

như điểm chuẩn này chỉ ra: nhập mô tả hình ảnh ở đây

Tôi đã chạy điểm chuẩn trên máy của mình với python 2.7 cho hai giải pháp trên (màu xanh: trăn nguyên chất, giải pháp đầu tiên) (giải pháp màu đỏ, numpy) và cho giải pháp chuẩn dựa trên itemgetter()(màu đen, giải pháp tham chiếu). Điểm chuẩn tương tự với python 3.5 cho thấy các phương thức so sánh giống hệt trường hợp python 2.7 được trình bày ở trên


+1 rất mạnh. Tôi thích điểm chuẩn của các giải pháp được đề xuất và các quy tắc của ngón tay cái mà bạn đã tóm tắt. Như tôi đã đề xuất trong một câu trả lời khác bên dưới, bạn có thể cung cấp (hoặc liên kết đến) mã kiểm tra của mình để người khác có thể sao chép kết quả của bạn không? Máy móc và thư viện thay đổi theo thời gian và nó sẽ cho phép so sánh với các giải pháp khác.
Rakurai

3
Tôi nghĩ rằng có thể có một lỗi đánh máy: xrange. Nó không phải là phạm vi?
Lindsay Fowler

6
@LindsayFowler xrange()hiện không được chấp nhận, bạn có thể sử dụngrange()
davide

np.argmin không hoạt động cho phao. chỉ đề xuất đầu tiên hoạt động trên ints và float.
jimh

Tôi nghĩ bạn đang nhầm, hãy thử import numpy as np; x = [2.3, -1.4]; np.argmin(x). Bạn cũng sẽ thấy nó argminhoạt động trên phao
gg349

332

Bạn có thể tìm thấy chỉ số và giá trị tối thiểu / tối đa cùng một lúc nếu bạn liệt kê các mục trong danh sách, nhưng thực hiện tối thiểu / tối đa trên các giá trị ban đầu của danh sách. Thích như vậy:

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

Bằng cách này, danh sách sẽ chỉ được duyệt một lần trong tối thiểu (hoặc tối đa).


110
Hoặc sử dụng lambda:key=lambda p: p[1]
scry

116

Nếu bạn muốn tìm chỉ số tối đa trong danh sách các số (có vẻ như trường hợp của bạn), thì tôi khuyên bạn nên sử dụng numpy:

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

Trong trường hợp có nhiều lần xuất hiện của các giá trị tối đa, các chỉ số tương ứng với lần xuất hiện đầu tiên được trả về.
Cohensius

41

Có thể một giải pháp đơn giản hơn là biến mảng các giá trị thành một mảng giá trị, các cặp chỉ số và lấy tối đa / phút của giá trị đó. Điều này sẽ đưa ra chỉ số lớn nhất / nhỏ nhất có max / min (tức là các cặp được so sánh bằng cách so sánh phần tử đầu tiên và sau đó so sánh phần tử thứ hai nếu phần tử thứ nhất giống nhau). Lưu ý rằng thực sự không cần thiết phải tạo mảng, vì min / max cho phép các trình tạo làm đầu vào.

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

Sẽ cung cấp cho bạn chỉ số đầu tiên tối thiểu.


18

Tôi nghĩ rằng điều tốt nhất để làm là chuyển đổi danh sách thành a numpy arrayvà sử dụng chức năng này:

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

14

Tôi cũng quan tâm đến điều này và so sánh một số giải pháp được đề xuất bằng perfplot (một dự án thú cưng của tôi).

Hóa ra là argmin của Numpy ,

numpy.argmin(x)

là phương pháp nhanh nhất cho các danh sách đủ lớn, ngay cả với việc chuyển đổi ngầm định từ đầu vào listsang a numpy.array.

nhập mô tả hình ảnh ở đây


Mã để tạo cốt truyện:

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

Lưu ý rằng kết luận tương tự đã được đăng ở trên trong câu trả lời của tôi, hơn 2 năm trước, với nhiều thông tin hơn về thời điểm và lý do argmin có thể được sử dụng hay không. Xem xét xóa câu trả lời, điều này cũng không mang lại công đức cho những gì đã được đề xuất trên cùng trang này. Cũng xem xét xem xét các câu trả lời khác của bạn về SO cho hành vi tương tự: bạn dường như không trích dẫn câu trả lời thực tế cung cấp giải pháp tốt nhất trong các phân tích hiệu suất của bạn. Điều này khá tệ, đặc biệt đối với ai đó có đại diện> 10K đã tồn tại đủ lâu để biết rõ hơn.
gg349

@ gg349, những điểm rất tốt, nhưng anh ấy cung cấp mã nguồn để tạo kết quả, làm cho điều này dễ tái tạo và thích ứng để so sánh các giải pháp khác. Tôi đồng ý rằng anh ta có thể xem xét loại bỏ câu trả lời này như một bản sao, nhưng có lẽ bạn có thể thêm giá trị cho câu trả lời của mình bằng cách bao gồm hoặc liên kết đến mã bạn đã sử dụng?
Rakurai

8

Sử dụng một mảng numpy và hàm argmax ()

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

8

Sau khi bạn nhận được các giá trị tối đa, hãy thử điều này:

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

Đơn giản hơn nhiều so với rất nhiều lựa chọn.


6

Tôi nghĩ rằng câu trả lời ở trên giải quyết vấn đề của bạn nhưng tôi nghĩ tôi sẽ chia sẻ một phương pháp mang lại cho bạn mức tối thiểu và tất cả các chỉ số tối thiểu xuất hiện trong đó.

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

Điều này vượt qua danh sách hai lần nhưng vẫn khá nhanh. Tuy nhiên, nó hơi chậm hơn so với việc tìm chỉ số của lần chạm đầu tiên tối thiểu. Vì vậy, nếu bạn chỉ cần một trong những cực tiểu, hãy sử dụng giải pháp của Matt Anderson , nếu bạn cần tất cả, hãy sử dụng giải pháp này.


1
Tôi thích điều này bởi vì nó sử dụng Python cơ bản và tôi thấy việc hiểu danh sách dễ hiểu hơn itemgetter, lambda, v.v. (và đủ linh hoạt để giải quyết nhiều nhiệm vụ khác nhau, chẳng hạn như ....)
James

nguyên. Tôi thích điều này.
Dev_Man

6

Sử dụng chức năng của mô-đun numpy numpy.where

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

Đối với chỉ số giá trị tối thiểu:

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

Đối với chỉ số giá trị tối đa:

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

Trên thực tế, chức năng này mạnh hơn nhiều. Bạn có thể đặt ra tất cả các loại hoạt động boolean Đối với chỉ số giá trị trong khoảng từ 3 đến 60:

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

chỉ số trong python bắt đầu từ 0. chỉ số được trả về sẽ là 6 (cho 65), trong khi mã của bạn trả về 7 (câu hỏi của OP là "Lấy chỉ mục ...")
tagoma

Trong lệnh, tôi đã truy vấn chỉ mục có giá trị tối thiểu (ở đây: 1) có chỉ số IS 7. 65 là giá trị tối đa của các phần tử trong mảng. Nếu bạn nhập: n.where (x == x.max ()) [0] bạn sẽ nhận được chỉ số tối đa. giá trị là 65 ở đây. Chỉ số của nó sẽ được đưa ra là 6
Ishan Tomar

sử dụng numpy: có thể bị cấm trong ứng dụng này. Nhưng nếu bạn định sử dụng numpy, bạn sẽ tốt hơn nếu chỉ sử dụng argmin()thay vì những gì bạn đã làm ở đây.
RBF06

Cảm ơn @ RBF06 tôi sẽ kiểm tra nó.
Ishan Tomar

5

Điều này chỉ đơn giản là có thể sử dụng hàm dựng sẵn enumerate()max()hàm và keyđối số tùy chọn của max()hàm và biểu thức lambda đơn giản:

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

Trong các tài liệu cho max()nó nói rằng keyđối số mong đợi một hàm như trong list.sort()hàm. Xem thêm Cách sắp xếp .

Nó hoạt động tương tự cho min(). Btw nó trả về giá trị tối đa / tối thiểu đầu tiên.


Câu trả lời muộn nhưng tốt nhất (nếu bạn không cần tốc độ).
mmj

5

Giả sử bạn có một danh sách như:

a = [9,8,7]

Hai phương pháp sau đây là những cách khá nhỏ gọn để có được một tuple với phần tử tối thiểu và chỉ mục của nó. Cả hai đều mất một thời gian tương tự để xử lý. Tôi thích phương pháp zip hơn, nhưng đó là sở thích của tôi.

phương pháp 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)

phương pháp liệt kê

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

Miễn là bạn biết cách sử dụng lambda và đối số "khóa", một giải pháp đơn giản là:

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

Rất sạch sẽ! Và không giống như câu trả lời được chấp nhận, đây là sự thật O (n), phải không? Tôi biết rằng O (2n) được coi là O (n), nhưng đối với rất lớn, nnó có thể chậm hơn đáng kể.
kevlarr

4

Đơn giản như thế :

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

index = stuff.index(max(stuff))

3

Tại sao phải thêm chỉ số đầu tiên và sau đó đảo ngược chúng? Hàm Enum Cả () chỉ là trường hợp đặc biệt của việc sử dụng hàm zip (). Hãy sử dụng nó theo cách thích hợp:

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

Chỉ là một bổ sung nhỏ cho những gì đã được nói. values.index(min(values))dường như trả về chỉ số nhỏ nhất của min. Sau đây có chỉ số lớn nhất:

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

Dòng cuối cùng có thể bị bỏ qua nếu tác dụng phụ của việc đảo ngược tại chỗ không quan trọng.

Lặp đi lặp lại qua tất cả các lần xuất hiện

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

Vì lợi ích của ngắn gọn. Có lẽ là một ý tưởng tốt hơn để lưu trữ min(values), values.count(min)bên ngoài vòng lặp.


2
reversed(…)thay vì ….reverse()có khả năng thích hợp hơn vì nó không biến đổi và trả về một trình tạo nào. Và tất cả các lần xuất hiện cũng có thể làminv = min(values); indices = [i for i, v in enumerate(values) if v == minv]
HoverHell

2

Một cách đơn giản để tìm các chỉ mục có giá trị tối thiểu trong danh sách nếu bạn không muốn nhập các mô-đun bổ sung:

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

Sau đó chọn ví dụ đầu tiên:

choosen = indexes_with_min_value[0]

1

Không có đại diện đủ cao để bình luận về câu trả lời hiện có.

Nhưng đối với https://stackoverflow.com/a/11825864/3920439 trả lời

Điều này hoạt động cho số nguyên, nhưng không hoạt động cho mảng phao (ít nhất là trong python 3.6) Nó sẽ tăng TypeError: list indices must be integers or slices, not float


0

https://docs.python.org/3/l Library / fiances.html # max

Nếu nhiều mục là tối đa, hàm sẽ trả về mục đầu tiên gặp phải. Điều này phù hợp với các công cụ bảo quản ổn định sắp xếp khác nhưsorted(iterable, key=keyfunc, reverse=True)[0]

Để có được nhiều hơn chỉ là lần đầu tiên sử dụng phương pháp sắp xếp.

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

Cái này thì sao:

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

Nó tạo ra một từ điển từ các mục trong adưới dạng các khóa và các chỉ mục của chúng dưới dạng các giá trị, do đó dict(zip(a,range(len(a))))[max(a)]trả về giá trị tương ứng với khóa max(a)là chỉ số của mức tối đa trong a. Tôi là người mới bắt đầu với python nên tôi không biết về độ phức tạp tính toán của giải pháp này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.