web-dev-qa-db-ja.com

Pythonでソートされた配列のインデックスを取得する方法

私は数値リストを持っています:

myList = [1, 2, 3, 100, 5]

このリストをソートして[1, 2, 3, 5, 100]を取得すると、私が欲しいのは、ソートされた順序で元のリストからの要素のインデックス、つまり[0, 1, 2, 4, 3] ---値とインデックスの両方を返すMATLABのソート関数です。

163
Gyan

Numpyを使用している場合、argsort()関数を使用できます。

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

http://docs.scipy.org/doc/numpy/reference/generated/numpy.argsort.html

これは、配列またはリストをソートする引数を返します。

157
Matthew Lewis

次のようなもの:

>>> 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 ...]リスト内包表記を使用して抽出されます。

119
myList = [1, 2, 3, 100, 5]    
sorted(range(len(myList)),key=myList.__getitem__)

[0, 1, 2, 4, 3]
65
robert king

enumerateの答えは素晴らしいですが、私は個人的にはラムダが値でソートするのが好きではありません。次の例では、インデックスと値を逆にして、並べ替えます。したがって、最初に値でソートし、次にインデックスでソートします。

sorted((e,i) for i,e in enumerate(myList))
18
Ant6n

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はタプルになります)

または、itemgettermodule`からoperatorを使用します。

from operator import itemgetter
sorted(enumerate(a), key=itemgetter(1))
11
Matt

Numpyを使用したくない場合は、

sorted(range(len(seq)), key=seq.__getitem__)

here で示されているように、最速です。

4
mab

perfplot (私のプロジェクト)でこれらの簡単なパフォーマンスチェックを行いましたが、numpy(ログスケールに注意してください)以外を推奨するのは難しいことがわかりました。

enter image description here


プロットを再現するコード:

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,
)
2
Nico Schlömer

基本的に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です。

ソートされた配列/リストで要素が持つインデックスを取得する

この場合、argsorttwiceを適用する必要があります。

>>> arr = np.array([3, 1, 2, 4])
>>> np.argsort(np.argsort(arr))
array([2, 0, 1, 3], dtype=int64)

この場合 :

  • オリジナルの最初の要素は3であり、これは3番目に大きい値であるため、ソートされた配列/リストにインデックス2があるため、最初の要素は2になります。
  • 元の2番目の要素は1であり、これは最小値であるため、ソートされた配列/リストにインデックス0があるため、2番目の要素は0になります。
  • オリジナルの3番目の要素は2であり、これは2番目に小さい値であるため、ソートされた配列/リストにインデックス1があるため、3番目の要素は1です。
  • オリジナルの4番目の要素は4で、これは最大値であるため、ソートされた配列/リストにインデックス3が含まれ、最後の要素は3になります。
1
MSeifert

他の答えは間違っています。

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)を提供します。

1
shahar_m

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
Aditya kumar

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

`

0
Jai dewani