私は数値リストを持っています:
myList = [1, 2, 3, 100, 5]
このリストをソートして[1, 2, 3, 5, 100]
を取得すると、私が欲しいのは、ソートされた順序で元のリストからの要素のインデックス、つまり[0, 1, 2, 4, 3]
---値とインデックスの両方を返すMATLABのソート関数です。
Numpyを使用している場合、argsort()関数を使用できます。
>>> import numpy
>>> numpy.argsort(myList)
array([0, 1, 2, 4, 3])
http://docs.scipy.org/doc/numpy/reference/generated/numpy.argsort.html
これは、配列またはリストをソートする引数を返します。
次のようなもの:
>>> myList = [1, 2, 3, 100, 5]
>>> [i[0] for i in sorted(enumerate(myList), key=lambda x:x[1])]
[0, 1, 2, 4, 3]
enumerate(myList)
は(index、value)のタプルを含むリストを提供します:
[(0, 1), (1, 2), (2, 3), (3, 100), (4, 5)]
リストを並べ替えるには、sorted
に渡し、並べ替えキーを抽出する関数を指定します(各タプルの2番目の要素。これがlambda
の目的です。最後に、各sorted要素の元のインデックスは[i[0] for i in ...]
リスト内包表記を使用して抽出されます。
myList = [1, 2, 3, 100, 5]
sorted(range(len(myList)),key=myList.__getitem__)
[0, 1, 2, 4, 3]
enumerate
の答えは素晴らしいですが、私は個人的にはラムダが値でソートするのが好きではありません。次の例では、インデックスと値を逆にして、並べ替えます。したがって、最初に値でソートし、次にインデックスでソートします。
sorted((e,i) for i,e in enumerate(myList))
enumerate
およびitemgetter
の回答を更新しました:
sorted(enumerate(a), key=lambda x: x[1])
# [(0, 1), (1, 2), (2, 3), (4, 5), (3, 100)]
リストを一緒に圧縮します:タプルの最初の要素がインデックスになり、2番目が値になります(その後、タプルx[1]
の2番目の値を使用してソートし、xはタプルになります)
または、itemgetter
module`からoperator
を使用します。
from operator import itemgetter
sorted(enumerate(a), key=itemgetter(1))
perfplot (私のプロジェクト)でこれらの簡単なパフォーマンスチェックを行いましたが、numpy(ログスケールに注意してください)以外を推奨するのは難しいことがわかりました。
プロットを再現するコード:
import perfplot
import numpy
def sorted_enumerate(seq):
return [i for (v, i) in sorted((v, i) for (i, v) in enumerate(seq))]
def sorted_enumerate_key(seq):
return [x for x, y in sorted(enumerate(seq), key=lambda x: x[1])]
def sorted_range(seq):
return sorted(range(len(seq)), key=seq.__getitem__)
def numpy_argsort(x):
return numpy.argsort(x)
perfplot.save(
"argsort.png",
setup=lambda n: numpy.random.Rand(n),
kernels=[sorted_enumerate, sorted_enumerate_key, sorted_range, numpy_argsort],
n_range=[2 ** k for k in range(15)],
xlabel="len(x)",
logx=True,
logy=True,
)
基本的にargsort
を実行する必要があります。必要な実装は、外部ライブラリ(NumPyなど)を使用するか、依存関係のない純粋なPythonを維持するかによって異なります。
自問する必要がある質問は次のとおりです。
残念ながら、質問の例では、両方が同じ結果をもたらすため、何が望ましいかが明確になりません。
>>> arr = np.array([1, 2, 3, 100, 5])
>>> np.argsort(np.argsort(arr))
array([0, 1, 2, 4, 3], dtype=int64)
>>> np.argsort(arr)
array([0, 1, 2, 4, 3], dtype=int64)
argsort
実装の選択NumPyを自由に使用できる場合は、単に関数 numpy.argsort
またはメソッド numpy.ndarray.argsort
を使用できます。
NumPyを使用しない実装は、他のいくつかの回答で既に言及されているため、 ベンチマークの回答 に従って、最速のソリューションを要約します
def argsort(l):
return sorted(range(len(l)), key=l.__getitem__)
配列/リストをソートするインデックスを取得するには、配列またはリストでargsort
を呼び出すだけです。ここではNumPyバージョンを使用していますが、Python実装でも同じ結果が得られるはずです
>>> arr = np.array([3, 1, 2, 4])
>>> np.argsort(arr)
array([1, 2, 0, 3], dtype=int64)
結果には、ソートされた配列を取得するために必要なインデックスが含まれます。
ソートされた配列は[1, 2, 3, 4]
であるため、argsorted配列には元の要素のインデックスが含まれます。
1
であり、元のインデックス1
にあるため、結果の最初の要素は1
です。2
は元のインデックス2
にあるため、結果の2番目の要素は2
です。3
は元のインデックス0
にあるため、結果の3番目の要素は0
です。4
で、元のインデックス3
にあるため、結果の最後の要素は3
です。この場合、argsort
twiceを適用する必要があります。
>>> arr = np.array([3, 1, 2, 4])
>>> np.argsort(np.argsort(arr))
array([2, 0, 1, 3], dtype=int64)
この場合 :
3
であり、これは3番目に大きい値であるため、ソートされた配列/リストにインデックス2
があるため、最初の要素は2
になります。1
であり、これは最小値であるため、ソートされた配列/リストにインデックス0
があるため、2番目の要素は0
になります。2
であり、これは2番目に小さい値であるため、ソートされた配列/リストにインデックス1
があるため、3番目の要素は1
です。4
で、これは最大値であるため、ソートされた配列/リストにインデックス3
が含まれ、最後の要素は3
になります。他の答えは間違っています。
argsort
を1回実行するのは解決策ではありません。たとえば、次のコード:
import numpy as np
x = [3,1,2]
np.argsort(x)
array([2, 0, 1], dtype=int64)
を生成しますが、これは望んでいないものです。
答えは、argsort
を2回実行することです。
import numpy as np
x = [3,1,2]
np.argsort(np.argsort(x))
期待どおりarray([2, 0, 1], dtype=int64)
を提供します。
Numpyをnpとしてインポート
インデックス用
S=[11,2,44,55,66,0,10,3,33]
r=np.argsort(S)
[output]=array([5, 1, 7, 6, 0, 8, 2, 3, 4])
argsortは、ソートされた順序でSのインデックスを返します
値の場合
np.sort(S)
[output]=array([ 0, 2, 3, 10, 11, 33, 44, 55, 66])
0〜n-1のインデックスの別の配列を作成し、これを元の配列にZipし、元の値に基づいて並べ替えます
ar = [1,2,3,4,5]
new_ar = list(Zip(ar,[i for i in range(len(ar))]))
new_ar.sort()
`