简体   繁体   English

如何用(python)列表中的顺序替换数字

[英]How to replace numbers with order in (python) list

I have a list containing integers and want to replace them so that the element which previously contained the highest number now contains a 1, the second highest number set to 2, etc etc. 我有一个包含整数的列表,并希望替换它们,以便先前包含最高数字的元素现在包含1,第二个最高数字设置为2,等等。

Example: [5, 6, 34, 1, 9, 3] should yield [4, 3, 1, 6, 2, 5] . 例如: [5, 6, 34, 1, 9, 3]应该产生[4, 3, 1, 6, 2, 5]

I personally only care about the first 9 highest numbers by I thought there might be a simple algorithm or possibly even a python function to do take care of this task? 我个人只关心前九个最高的数字我认为可能有一个简单的算法或甚至可能是python函数来处理这个任务?

Edit: I don't care how duplicates are handled. 编辑:我不关心如何处理重复项。

A fast way to do this is to first generate a list of tuples of the element and its position: 一种快速的方法是首先生成元素的元组列表及其位置:

sort_data = [(x,i) for i,x in enumerate(data)]

next we sort these elements in reverse : 接下来我们将这些元素reverse排序:

sort_data = sorted(sort_data,reverse=True)

which generates (for your sample input): 生成(用于您的样本输入):

>>> sort_data
[(34, 2), (9, 4), (6, 1), (5, 0), (3, 5), (1, 3)]

and nest we need to fill in these elements like: 和巢我们需要填写这些元素,如:

result = [0]*len(data)
for i,(_,idx) in enumerate(sort_data,1):
    result[idx] = i

Or putting it together: 或者把它放在一起:

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

this approach works in O(n log n) with n the number of elements in data . 这种方法在输出工作(N log n)的与元件数n data

A more compact algorithm (in the sense that no tuples are constructed for the sorting) is: 一个更紧凑的算法(在没有为排序构造元组的意义上)是:

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

Assuimg you do not have any duplicates, the following list comprehension will do: 假设您没有任何重复项,以下列表理解将会:

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]

To understand how it works, you can break it up into pieces like so: 要了解它是如何工作的,你可以把它分成几块:

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]

Another option, you can use rankdata function from scipy , and it provides options to handle duplicates: 另一种选择,你可以使用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])

Using numpy.argsort : 使用numpy.argsort

numpy.argsort returns the indices that would sort an array. 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])

A short, log-linear solution using pure Python, and no look-up tables. 使用纯Python的简短的对数线性解决方案,没有查找表。

The idea: store the positions in a list of pairs, then sort the list to reorder the positions. 想法:将位置存储在成对列表中,然后对列表进行排序以重新排序位置。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM