としてリストがあり [[4,5,6],[2,3,1]]
ます。今、私はに基づいてリストをソートしたいと思いlist[1]
ます [[6,4,5],[1,2,3]]
。だから基本的に私はソート2,3,1
し、の順序を維持していlist[0]
ます。
検索中に、すべてのリストの最初の要素に基づいてソートする関数を取得しましたが、これはそうではありません。また、リストを再作成して関数を使用したくありません[[4,2],[5,3],[6,1]]
。
[4, 5, 6]
とは 2 つの異なる目的に役立つため、 2 つの[2, 3, 1]
引数を取る関数を作成します。並べ替えられるリストと、並べ替えによって順序が決定されるリストです。並べ替えたリストのみを返します。
この回答には、並べ替えの順列リストを作成するための 3 つの異なるソリューションのタイミングがあります。最速のオプションを使用すると、次のソリューションが得られます。
def pyargsort(seq):
return sorted(range(len(seq)), key=seq.__getitem__)
def using_pyargsort(a, b):
"Reorder the list a the same way as list b would be reordered by a normal sort"
return [a[i] for i in pyargsort(b)]
print using_pyargsort([4, 5, 6], [2, 3, 1]) # [6, 4, 5]
このメソッドは、同じことをより高速に行うnumpypyargsort
メソッドに触発されています。Numpy には、配列をインデックスとして使用できる高度なインデックス操作もあり、配列の並べ替えを非常に迅速に行うことができます。 argsort
したがって、速度の必要性が高い場合は、このnumpyソリューションの方が高速であると想定できます。
import numpy as np
def using_numpy(a, b):
"Reorder the list a the same way as list b would be reordered by a normal sort"
return np.array(a)[np.argsort(b)].tolist()
print using_numpy([4, 5, 6], [2, 3, 1]) # [6, 4, 5]
ただし、短いリスト (長さ < 1000) の場合、このソリューションは実際には最初のソリューションよりも遅くなります。これは、最初にa
andb
リストをarray
に変換してから、結果を に変換してlist
から返すためです。代わりに、アプリケーション全体で numpy 配列を使用しているため、前後に変換する必要がないと仮定すると、次のソリューションが得られます。
def all_numpy(a, b):
"Reorder array a the same way as array b would be reordered by a normal sort"
return a[np.argsort(b)]
print all_numpy(np.array([4, 5, 6]), np.array([2, 3, 1])) # array([6, 4, 5])
関数は、関数all_numpy
よりも最大 10 倍速く実行されusing_pyargsort
ます。
次の対数グラフは、これら 3 つのソリューションを他の回答の 2 つの代替ソリューションと比較しています。引数は、同じ長さのランダムにシャッフルされた 2 つの範囲であり、関数はすべて同じ順序のリストを受け取ります。関数の実行にかかる時間だけを計っています。説明のために、numpy をロードするための 60 ミリ秒のオーバーヘッドが時間に追加される numpy ソリューションごとに追加のグラフ行を追加しました。
ご覧のとおり、すべて numpy のソリューションは、他のソリューションよりも桁違いに優れています。Python からの変換list
とその逆は、比較するとソリューションの速度がusing_numpy
大幅に低下しますが、大きなリストでは純粋な Python よりも優れています。
約 1'000'000 のリストの長さの場合、using_pyargsort
2.0 秒かかり、using_nympy
+ オーバーヘッドはわずか 1.3 秒ですが、all_numpy
+ オーバーヘッドは 0.3 秒です。
あなたが説明する並べ替えは、達成するのが非常に簡単ではありません。私が考えることができる唯一の方法は、zip
作成したくないと言うリストを作成するために使用することです。
lst = [[4,5,6],[2,3,1]]
# key = operator.itemgetter(1) works too, and may be slightly faster ...
transpose_sort = sorted(zip(*lst),key = lambda x: x[1])
lst = zip(*transpose_sort)
この制約には理由がありますか?
(また、本当にしたい場合は、これをすべて 1 行で実行できることに注意してください。
lst = zip(*sorted(zip(*lst),key = lambda x: x[1]))
これにより、タプルのリストも生成されます。リストのリストが本当に必要な場合は、次map
の結果 を得ることができます。
lst = map(list, lst)
または、リスト内包表記も同様に機能します。
lst = [ list(x) for x in lst ]
2 番目のリストに重複が含まれていない場合は、次のようにすることができます。
l = [[4,5,6],[2,3,1]] #the list
l1 = l[1][:] #a copy of the to-be-sorted sublist
l[1].sort() #sort the sublist
l[0] = [l[0][l1.index(x)] for x in l[1]] #order the first sublist accordingly
(これはサブリスト l[1] を保存するので、入力リストが巨大な場合は悪い考えかもしれません)
これはどう:
a = [[4,5,6],[2,3,1]]
[a[0][i] for i in sorted(range(len(a[1])), key=lambda x: a[1][x])]
これは、numpy を使用せずに、zip を使用せずに、numpy が行う主要な方法を使用します。
numpy を使用することも、高速で移動することも、巨大な構造の最も安価な方法ではないようです。残念ながら、この.sort()
メソッドは型に組み込まれておりlist
、リスト内の要素へのハードワイヤード アクセスを使用します (オーバーライド__getitem__()
などはここでは効果がありません)。
sort()
したがって、1 つの値に従って 2 つ以上のリストをソートする独自の実装を実装できます。これは基本的に numpy が行うことです。
または、並べ替える値のリストを作成し、それを並べ替えて、並べ替えられた元のリストを再作成することもできます。