使用列表中的 max()/min() 获取返回的最大或最小项的索引
- 2025-01-13 08:52:00
- admin 原创
- 30
问题描述:
我在列表上使用 Python 的max
和min
函数来实现极小最大算法,我需要max()
或返回的值的索引min()
。换句话说,我需要知道哪个动作产生了最大值(在第一个玩家的回合)或最小值(第二个玩家)。
for i in range(9):
new_board = current_board.new_board_with_move([i / 3, i % 3], player)
if new_board:
temp = min_max(new_board, depth + 1, not is_min_level)
values.append(temp)
if is_min_level:
return min(values)
else:
return max(values)
我需要能够返回最小值或最大值的实际索引,而不仅仅是值。
解决方案 1:
假设您有一个列表values = [3,6,1,5]
,并且需要最小元素的索引,index_min = 2
在这种情况下为 ie。
避免使用其他答案中提供的解决方案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
数组的内存复制
正如该基准测试指出的那样:
我已经在我的机器上使用 Python 2.7 对上述两种解决方案(蓝色:纯 Python,第一个解决方案)(红色,numpy 解决方案)和基于itemgetter()
(黑色,参考解决方案)的标准解决方案进行了基准测试。使用 Python 3.5 进行的相同基准测试表明,这些方法与上面介绍的 Python 2.7 案例完全相同
解决方案 2:
用 找到最小值,min()
然后用 找到该值的索引.index()
:
values.index(min(values))
或者最大值:
values.index(max(values))
如果您的列表包含最小值或最大值的重复,这将返回第一个的索引。
解决方案 3:
如果您枚举列表中的项目,但对列表的原始值执行最小/最大操作,则可以同时找到最小/最大索引和值。如下所示:
import operator
min_index, min_value = min(enumerate(values), key=operator.itemgetter(1))
max_index, max_value = max(enumerate(values), key=operator.itemgetter(1))
这样,对于最小值(或最大值),列表只会遍历一次。
解决方案 4:
使用 NumPynp.argmin()
或np.argmax()
函数:
import numpy as np
ind = np.argmax(mylist)
解决方案 5:
将值数组转换为 (值,索引) 对数组,然后取其中的最大值/最小值。这将返回具有最大值/最小值的最大/最小索引(即,首先比较值,然后如果值相同则比较索引,以此来比较对)。
values = [3, 5, 4, 5]
m, i = max((v, i) for i, v in enumerate(values))
print((m, i)) # (5, 3)
解决方案 6:
我使用perfplot (我的一个业余项目)在 Python 3.11 上对主要答案进行了基准测试,结果表明
values.index(min(values))
是最快的(越低越好):
除非你的数组已经是一个 numpy 数组。
生成图表的代码:
import numpy as np
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 np.argmin(a)
def index_min(a):
return a.index(min(a))
b = perfplot.bench(
setup=lambda n: np.random.rand(n).tolist(),
kernels=[
min_enumerate,
min_enumerate_itemgetter,
getitem,
np_argmin,
index_min,
],
labels = [
"key=lambda x: x[1]",
"key=itemgetter(1)",
"key=.__getitem__",
"np.argmin()",
".index()"
],
xlabel="len(list)",
n_range=[2**k for k in range(20)],
)
b.show()
解决方案 7:
有两个答案(1、2 )包含基准,但由于某种原因,它们都没有将其纳入基准,尽管这是在这些答案之前至少 2 年前发布的已接受答案中提出的。list.index()
list.index()
是本页给出的最快的选项,包括enumerate
(涉及它的所有版本)__getitem__
和numpy.argmin
。
此外,如果列表具有非唯一最小值,并且您想要获取出现最小值的所有索引,list.index
则 while 循环的效果优于其他选项(例如 numpy 和enumerate
)。请注意,您可以通过传递起点(即 的第二个参数list.index
)来限制其搜索从特定索引开始,这对于性能至关重要,因为我们不想在 while 循环的每次迭代中从头开始搜索。
# get the index of the minimum value
my_list = [1, 2, 0, 1]
idxmin = my_list.index(min(my_list))
print(idxmin) # 2
# get all indices where the min value occurs
my_list = [1, 2, 3, 1]
idxmins = []
min_val = min(my_list)
pos = -1
while True:
try:
pos = my_list.index(min_val, pos+1)
# ^^^^^ <---- pick up where we left off in the previous iteration
idxmins.append(pos)
except ValueError:
break
print(idxmins) # [0, 3]
以下基准测试(在 Python 3.11.4 和 numpy 1.25.2 上执行)表明,list.index
无论列表长度如何,它的速度几乎是所有其他选项的两倍。左图还显示,对于长列表,其性能与(和)getitem
相同,这表明gg349和Nico的基准测试已经过时了。enumerate
`numpy.argmin`
右图显示,如果最小值不唯一,而我们想要找到最小值的所有索引,那么list.index
上面概述的 while 循环比涉及或 numpy 的竞争选项表现要好得多enumerate
,尤其是对于长列表。
生成上图所用的代码:
from operator import itemgetter
import numpy as np
import matplotlib.pyplot as plt
import perfplot
def enumerate_1(a):
return min(enumerate(a), key=itemgetter(1))[0]
def np_argmin_1(a):
return np.argmin(a)
def getitem(a):
return min(range(len(a)), key=a.__getitem__)
def list_index_1(a):
return a.index(min(a))
def enumerate_2(a):
min_val = min(a)
return [i for i, v in enumerate(a) if v == min_val]
def np_argmin_2(a):
arr = np.array(a)
return np.arange(len(a))[arr==arr.min()]
def list_index_2(a):
result = []
min_val = min(a)
pos = -1
while True:
try:
pos = a.index(min_val, pos+1)
result.append(pos)
except ValueError:
break
return result
kernels_list = [[enumerate_1, list_index_1, np_argmin_1, getitem],
[enumerate_2, list_index_2, np_argmin_2]]
n_range = [2**k for k in range(1, 20)]
su = lambda n: list(range(n, 0, -1))
titles = ['Get index of a unique min value',
'Get indices of a non-unique min value']
labels = ['enumerate', 'list_index', 'np_argmin', 'getitem']
xlabel = 'List length'
fig, axs = plt.subplots(1, 2, figsize=(12, 5), facecolor='white', dpi=60)
for ax, ks, t in zip(axs, kernels_list, titles):
plt.sca(ax)
perfplot.plot(ks, n_range, su, None, labels, xlabel, t, relative_to=1)
ax.xaxis.set_tick_params(labelsize=13)
plt.setp(axs, ylim=(0, 5), yticks=range(1, 6),
xlim=(1, 1100000), xscale='log', xticks=[1, 100, 10000, 1000000]);
fig.tight_layout();
fig.savefig('benchmark.png', dpi=60);
解决方案 8:
如果您需要最小值的所有索引(因为最小值可能在列表中出现多次):
minval = min(mylist)
ind = [i for i, v in enumerate(mylist) if v == minval]
解决方案 9:
获得最大值后,尝试以下操作:
max_val = max(list)
index_max = list.index(max_val)
比很多选项简单得多。
解决方案 10:
这可以使用内置函数enumerate()
以及函数的max()
可选参数和简单表达式来实现:key=
`max()`lambda
values = [1, 5, 10]
max_index, max_value = max(enumerate(values), key=lambda v: v[1])
# => (2, 10)
在文档中,max()
它表示key=
参数需要一个类似于list.sort()
函数的函数。另请参阅排序方法。
它的工作原理相同min()
。顺便说一下,它返回第一个最大/最小值。
解决方案 11:
Pandas 现在有一个更温和的解决方案,尝试一下:
df[column].idxmax()
解决方案 12:
使用 numpy 数组和argmax()
函数
a = np.array([1, 2, 3])
b = np.argmax(a)
print(b) # 2
解决方案 13:
使用 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])
解决方案 14:
假设你有一个列表,例如:
a = [9,8,7]
以下两种方法是获取具有最小元素及其索引的元组的非常紧凑的方法。 两种方法的处理时间都差不多。 我更喜欢 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)
解决方案 15:
您可以将 lambda 作为key=
参数传递给max()
/ min()
:
max_index = max(range(len(my_list)), key=lambda index: my_list[index])
解决方案 16:
为什么要先添加索引,然后再反转它们? 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)
解决方案 17:
就这么简单:
stuff = [2, 4, 8, 15, 11]
index = stuff.index(max(stuff))
解决方案 18:
假设您有一个以下列表my_list = [1,2,3,4,5,6,7,8,9,10]
,并且我们知道如果我们这样做max(my_list)
它将返回10
并将min(my_list)
返回1
。现在我们想要获取最大或最小元素的索引,我们可以执行以下操作。
my_list = [1,2,3,4,5,6,7,8,9,10]
max_value = max(my_list) # returns 10
max_value_index = my_list.index(max_value) # retuns 9
#to get an index of minimum value
min_value = min(my_list) # returns 1
min_value_index = my_list.index(min_value) # retuns 0
运行代码片段Hide results展开片段
解决方案 19:
https://docs.python.org/3/library/functions.html#max
如果多个项为最大值,则该函数返回遇到的第一个项。这与其他排序稳定性保持工具一致,例如sorted(iterable, key=keyfunc, reverse=True)[0]
要获取不仅仅是第一个遇到的结果,请使用排序方法。
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)]
解决方案 20:
只是对已经说过的内容做了一点补充。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)
在循环之外缓存可能是一个更好的主意。
解决方案 21:
如果您不想导入其他模块,有一种简单的方法可以在列表中查找具有最小值的索引:
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]
解决方案 22:
那这个呢:
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 的初学者,所以我不知道这个解决方案的计算复杂性。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)