4

必要な出力

「ごちゃ混ぜの」リストが与えられた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)

では、どうすればこれをより簡潔に書くことができますか?読みやすいリスト内包表記の解決策はありますか?

4

5 に答える 5

5
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
于 2012-09-14T00:27:58.273 に答える
4

これは私が思いついた最高のものです:

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

それはあなたの解決策よりも速いです、しかしそれはそれについてです。

于 2012-09-14T00:15:35.457 に答える
2

1行の理解がありますが、それは本当に醜いです:

>>> 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 の回答は読みやすく、ガベージの生成が少なくなります。

于 2012-09-14T00:31:45.250 に答える
2
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]
于 2012-09-14T00:33:25.053 に答える
2

統計計算を行っている場合は、おそらくある時点で numpy を使い始めるでしょう。numpy を使用すると、argsort の既存の実装を使用できます。

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

それは、unutbuの答えの派手なバージョンです。ナイトクラッカーの答えは次のように実装できます

>>> 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])
于 2012-09-14T03:27:40.287 に答える