У меня есть массив:
arr = [23,34,2,55,5,13,44,3]
и я хочу сохранить n самых больших чисел с их индексами.
например, для n = 2 я хочу
[(55,3), (44,6)]
Я не мог найти простой способ сделать это.
Я только нашел, как получить n самых больших элементов, используя nlargest
или n самых больших индексов, используя argpartition
.
Отказ от ответственности: нет простое решение — вы можете комбинировать enumerate
, sorted
, понимание генератора и нарезку списка:
n = 3
s = list(sorted( ((v,i) for i,v in enumerate([23,34,2,55,5,13,44,3]) ),reverse = True))[:n]
print(s)
Выход:
[(55, 3), (44, 6), (34, 1)]
Доку:
Генератор используется для переворачивания индекса и значения, полученного при перечислении, нарезка уменьшает количество результатов.
Вот решение на основе NumPy:
In [207]: arr
Out[207]: array([23, 34, 2, 55, 5, 13, 44, 3])
# sort array `arr` in increasing order
In [208]: arr_sorted = arr[arr.argsort()]
# slice largest 3 elements
In [209]: largest_3 = arr_sorted[-3:][::-1]
In [210]: largest_3
Out[210]: array([55, 44, 34])
# get the indices that would sort the array `arr` (in increasing order)
In [211]: arr_sorted_idx = arr.argsort()
# grab the largest 3 indices in accordance with [209]/[210]
In [212]: largest_3_idx = arr_sorted_idx[-3:][::-1]
In [213]: largest_3_idx
Out[213]: array([3, 6, 1])
largest_3_idx
— это индексы трех самых больших элементов в исходном массиве arr
.
Если вам вообще нужен результат в виде списка кортежей, используйте:
In [214]: list(zip(largest_3.tolist(), largest_3_idx.tolist()))
Out[214]: [(55, 3), (44, 6), (34, 1)]
Вот сокращенная версия Numpy:
n=3 #number of largest elements to get
a = np.array([23, 34, 2, 55, 5, 13, 44, 3])
idx = a.argsort()[:-n-1:-1] #Use argsort get sorted index and slice backwards
list(zip(a[idx], idx)) #zip and list for tuples
Выход:
[(55, 3), (44, 6), (34, 1)]
Давайте построим некоторые тайминги:
import numpy
import perfplot
def sb_numpy(a,n):
idx = a.argsort()[:-n-1:-1] #Use argsort get sorted index and slice backwards
return list(zip(a[idx], idx))
def pa_pyth(a,n):
return list(sorted( ((v,i) for i,v in enumerate(a) ),reverse = True))[:n]
perfplot.show(
setup=lambda n: numpy.random.randint(0,10e7, n),
kernels=[
lambda a: sb_numpy(a,3),
lambda a: pa_pyth(a,3)
],
labels=['sb_numpy', 'pa_pyth'],
n_range=[2**k for k in range(15)],
xlabel='N'
)
Выход:
Мне это тоже нравится... сортировка по убыванию. Спасибо @ Вен-Бен!
Мне нравится идея с зипом, и, возможно, мы сможем сделать
(-a).argsort()[:3]