【问题标题】:How to replace numbers with order in (python) list如何用(python)列表中的顺序替换数字
【发布时间】:2017-07-21 00:36:51
【问题描述】:

我有一个包含整数的列表并想要替换它们,以便以前包含最高数字的元素现在包含 1,第二大数字设置为 2,等等。

示例: [5, 6, 34, 1, 9, 3] 应该产生 [4, 3, 1, 6, 2, 5]

我个人只关心前 9 个最高的数字,因为我认为可能有一个简单的算法甚至可能是一个 python 函数来处理这个任务?

编辑:我不在乎如何处理重复。

【问题讨论】:

  • 能否提供您尝试的代码的sn-p。
  • 如果两个数相同怎么办?
  • tmp = sorted(input); output = [0] * len(input); for i in range(min(len(tmp), 9)): output[input.index(tmp[i])] = i 是我想到的,但我还没有测试过。这也不好处理重复。

标签: python arrays algorithm list sorting


【解决方案1】:

一种快速的方法是首先生成元素及其位置的元组列表:

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

这种方法在 O(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

【讨论】:

  • @Rawing:用于存储元素的原始位置。 Ev.Kounis 算法更优雅,但在 O(n^2 log n) 中运行,而在 O(n log n) 中运行。
【解决方案2】:

另一个选项,您可以使用scipy 中的rankdata 函数,它提供了处理重复项的选项:

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

【讨论】:

    【解决方案3】:

    假设您没有任何重复项,则可以使用以下列表理解:

    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]
    

    【讨论】:

    • 最好在 before 列表理解之前进行排序。就目前而言,它在每次迭代中对lst 进行排序。 repl.it 性能差异
    • Furthermore index(..)O(n) 中运行,因此这是一个 O(n^2 log n) 算法。
    • @WillemVanOnsem 我不太擅长计算复杂性。你是怎么得出的?如果index 在 O(n) 中运行,不只是 O(n^2) 吗?
    • @Ev.Kounis:现在它确实在 O(n^2) 中运行(因为排序步骤只执行一次)。由于indexO(n) 中运行,而您这样做 O(n) 次。
    • @WillemVanOnsem 哦,我明白了。谢谢。
    【解决方案4】:

    使用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])
    

    【讨论】:

    • 不确定我是否理解这一点,-np.array() 是做什么的,为什么 +1?
    • np.array(xs) 创建一个 numpy 数组。 -np.array(xs) 返回一个新数组,所有项目都被否定。
    【解决方案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]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-11
      • 1970-01-01
      • 2016-06-18
      • 1970-01-01
      • 1970-01-01
      • 2021-01-25
      • 2019-10-18
      • 1970-01-01
      相关资源
      最近更新 更多