【问题标题】:Given a "jumbled" list L, get a list where each element is the index of the corresponding element of L, if L was sorted给定一个“混乱”的列表 L,如果 L 已排序,则得到一个列表,其中每个元素都是 L 的相应元素的索引
【发布时间】:2012-09-14 00:12:43
【问题描述】:

期望的输出

我想要一个函数返回一个列表,如果l 已排序,则给定一个“混乱”列表l,每个元素都是l 的相应元素的索引。 (抱歉,我想不出一种不那么复杂的说法。)

示例

f([3,1,2]) = [2,0,1]

f([3,1,2,2,3]) = [3,0,1,2,4],因为排序后的输入是[1,2,2,3,3]

(这对于一些统计数据计算很有用。)

我的尝试

我想出了一种方法来执行此功能,但这是 python- 似乎应该有一个单行来执行此操作,或者至少是一种更清洁、更清晰的方法。

def getIndiciesInSorted(l):
    sortedL = sorted(l)
    outputList = []
    for num in l:
        sortedIndex = sortedL.index(num)
        outputList.append(sortedIndex)
        sortedL[sortedIndex] = None
    return outputList

l=[3,1,2,2,3] 
print getIndiciesInSorted(l)

那么,我怎样才能更简洁地写这个?是否有清晰的列表理解解决方案?

【问题讨论】:

  • 请注意,这与sorted(range(len(l)), key=lambda i: l[i]) 不同...(虽然这是我的第一个想法。)
  • @nightcracker 我知道,你的回答也是我的第一次尝试,所以我想我会发表评论让其他人知道这种方法是行不通的。

标签: python


【解决方案1】:
def argsort(seq):
    # http://stackoverflow.com/questions/3382352/3382369#3382369
    # http://stackoverflow.com/questions/3071415/3071441#3071441
    '''
    >>> seq=[1,3,0,4,2]
    >>> index=argsort(seq)
    [2, 0, 4, 1, 3]

    Given seq and the index, you can construct the sorted seq:
    >>> sorted_seq=[seq[x] for x in index]
    >>> assert sorted_seq == sorted(seq)

    Given the sorted seq and the index, you can reconstruct seq:
    >>> assert [sorted_seq[x] for x in argsort(index)] == seq
    '''
    return sorted(range(len(seq)), key=seq.__getitem__)

def f(seq):
    idx = argsort(seq)
    return argsort(idx)

print(f([3,1,2]))
# [2, 0, 1]

print(f([3,1,2,2,3]))
# [3, 0, 1, 2, 4]

注意,nightcracker 的功能更快:

def get_sorted_indices(l):
    sorted_positions = sorted(range(len(l)), key=l.__getitem__)
    result = [None for _ in range(len(l))]
    for new_index, old_index in enumerate(sorted_positions):
        result[old_index] = new_index
    return result

对于长列表,差异可能很大:

In [83]: import random
In [98]: l = [random.randrange(100) for _ in range(10000)]
In [104]: timeit get_sorted_indices(l)
100 loops, best of 3: 4.73 ms per loop

In [105]: timeit f(l)
100 loops, best of 3: 6.64 ms per loop

【讨论】:

  • 这会排序两次,如果速度是一个因素,我的版本可能会更快(另一方面,排序代码是用 C 编码的,所以实际上可能会让你的更快)。
【解决方案2】:

这是我想出的最好的:

def get_sorted_indices(l):
    sorted_positions = sorted(range(len(l)), key=l.__getitem__)
    result = [None for _ in range(len(l))]

    for new_index, old_index in enumerate(sorted_positions):
        result[old_index] = new_index

    return result

它比您的解决方案更快,但仅此而已。

【讨论】:

  • +1:确实,您的方法更快,尤其是对于较长的列表。 (PS。我认为[None for _ in len(l)]需要是[None for _ in range(len(l)]。另外,如果你把key = lambda ...改成key = l.__getitem__,代码会快一点。)
  • @unutbu:合并了您建议的更改。
  • 或者只是result = [None] * len(l)
  • @Warren 这更简洁,但列表乘法通常不是一个好主意。尽管在这种情况下会很好,但在一个有很多新 Pythonistas 的问答网站上,我倾向于认为最好不要演示列表乘法,以免有人试图概括它并最终为 Python SO 的巨大山峰做出贡献与 Python 中的共享引用有关的问题。
【解决方案3】:

有一个单行理解但是真的很丑:

>>> E, S = enumerate, sorted
>>> l = [3,1,2,2,3]
>>> [a for _,a in S((a,b) for b,(_,a) in E(S((a,b) for b,a in E(l))))]
[3, 0, 1, 2, 4]

Unutbu's answer 更容易阅读,产生的垃圾更少。

【讨论】:

    【解决方案4】:
    k = [3, 0, 1, 2, 4]
    initial = dict(zip(k, range(len(k)))) #{0: 1, 1: 2, 2: 3, 3: 0, 4: 4}
    sorted_initial = dict(zip(sorted(k), range(len(k)))) #{0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
    initial.update(sorted_initial) #{0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
    result = [initial[i] for i in k] #[3, 0, 1, 2, 4]
    

    【讨论】:

    • 这种方法的唯一困难是序列中的项目必须是可散列的。
    【解决方案5】:

    如果您在进行统计计算,您可能会在某个时候开始使用 numpy。使用 numpy,您可以使用 argsort 的现有实现:

    >>> from numpy import array
    >>> x = array([3, 1, 2, 2, 3])
    >>> x.argsort().argsort()
    array([3, 0, 1, 2, 4])
    

    这是 unutbu 答案的 numpy 版本。 nightcracker 的答案可以实现为

    >>> from numpy import array, empty_like, arange
    >>> x = array([3, 1, 2, 2, 3])
    >>> s = x.argsort()
    >>> r = empty_like(s)
    >>> r[s] = arange(x.size)
    >>> r
    array([3, 0, 1, 2, 4])
    

    【讨论】:

      猜你喜欢
      • 2013-11-14
      • 2014-02-16
      • 2017-01-07
      • 2019-12-03
      • 2017-12-26
      • 2022-12-05
      • 2014-05-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多