[英]How to replace numbers with order in (python) list
我有一個包含整數的列表,並希望替換它們,以便先前包含最高數字的元素現在包含1,第二個最高數字設置為2,等等。
例如: [5, 6, 34, 1, 9, 3]
應該產生[4, 3, 1, 6, 2, 5]
。
我個人只關心前九個最高的數字我認為可能有一個簡單的算法或甚至可能是python函數來處理這個任務?
編輯:我不關心如何處理重復項。
一種快速的方法是首先生成元素的元組列表及其位置:
sort_data = [(x,i) for i,x in enumerate(data)]
接下來我們將這些元素reverse
排序:
sort_data = sorted(sort_data,reverse=True)
生成(用於您的樣本輸入):
>>> sort_data
[(34, 2), (9, 4), (6, 1), (5, 0), (3, 5), (1, 3)]
和巢我們需要填寫這些元素,如:
result = [0]*len(data)
for i,(_,idx) in enumerate(sort_data,1):
result[idx] = i
或者把它放在一起:
def obtain_rank(data):
sort_data = [(x,i) for i,x in enumerate(data)]
sort_data = sorted(sort_data,reverse=True)
result = [0]*len(data)
for i,(_,idx) in enumerate(sort_data,1):
result[idx] = i
return result
這種方法在輸出工作(N log n)的與元件數n data
。
一個更緊湊的算法(在沒有為排序構造元組的意義上)是:
def obtain_rank(data):
sort_data = sorted(range(len(data)),key=lambda i:data[i],reverse=True)
result = [0]*len(data)
for i,idx in enumerate(sort_data,1):
result[idx] = i
return result
假設您沒有任何重復項,以下列表理解將會:
lst = [5, 6, 34, 1, 9, 3]
tmp_sorted = sorted(lst, reverse=True) # kudos to @Wondercricket
res = [tmp_sorted.index(x) + 1 for x in lst] # [4, 3, 1, 6, 2, 5]
要了解它是如何工作的,你可以把它分成幾塊:
lst = [5, 6, 34, 1, 9, 3]
# let's see what the sorted returns
print(sorted(lst, reverse=True)) # [34, 9, 6, 5, 3, 1]
# biggest to smallest. that is handy.
# Since it returns a list, i can index it. Let's try with 6
print(sorted(lst, reverse=True).index(6)) # 2
# oh, python is 0-index, let's add 1
print(sorted(lst, reverse=True).index(6) + 1) # 3
# that's more like it. now the same for all elements of original list
for x in lst:
print(sorted(lst, reverse=True).index(x) + 1) # 4, 3, 1, 6, 2, 5
# too verbose and not a list yet..
res = [sorted(lst, reverse=True).index(x) + 1 for x in lst]
# but now we are sorting in every iteration... let's store the sorted one instead
tmp_sorted = sorted(lst, reverse=True)
res = [tmp_sorted.index(x) + 1 for x in lst]
另一種選擇,你可以使用rankdata功能從scipy
,它提供了一些選項來處理重復:
from scipy.stats import rankdata
lst = [5, 6, 34, 1, 9, 3]
rankdata(list(map(lambda x: -x, lst)), method='ordinal')
# array([4, 3, 1, 6, 2, 5])
使用numpy.argsort
:
numpy.argsort
返回將對數組進行排序的索引。
>>> xs = [5, 6, 34, 1, 9, 3]
>>> import numpy as np
>>> np.argsort(np.argsort(-np.array(xs))) + 1
array([4, 3, 1, 6, 2, 5])
使用純Python的簡短的對數線性解決方案,沒有查找表。
想法:將位置存儲在成對列表中,然后對列表進行排序以重新排序位置。
enum1 = lambda seq: enumerate(seq, start=1) # We want 1-based positions
def replaceWithRank(xs):
# pos = position in the original list, rank = position in the top-down sorted list.
vp = sorted([(value, pos) for (pos, value) in enum1(xs)], reverse=True)
pr = sorted([(pos, rank) for (rank, (_, pos)) in enum1(vp)])
return [rank for (_, rank) in pr]
assert replaceWithRank([5, 6, 34, 1, 9, 3]) == [4, 3, 1, 6, 2, 5]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.