web-dev-qa-db-ja.com

別のリストの値に基づいてリストをソートしますか?

このような文字列のリストがあります。

X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
Y = [ 0,   1,   1,    0,   1,   2,   2,   0,   1]

次の出力を得るためにYからの値を使用してXをソートする最短の方法は何ですか?

["a", "d", "h", "b", "c", "e", "i", "f", "g"]

同じ「キー」を持つ要素の順序は関係ありません。私はfor構造の使用に頼ることができますが、もっと短い方法があるかどうか私は興味があります。助言がありますか?

279
Legend

最短コード

[x for _,x in sorted(Zip(Y,X))]

例:

X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
Y = [ 0,   1,   1,    0,   1,   2,   2,   0,   1]

Z = [x for _,x in sorted(Zip(Y,X))]
print(Z)  # ["a", "d", "h", "b", "c", "e", "i", "f", "g"]

一般的に言えば

[x for _, x in sorted(Zip(Y,X), key=lambda pair: pair[0])]

説明:

  1. Zip 2つのlists。
  2. sorted() を使用して、listに基づいて新しいソート済みのZipを作成します。
  3. リスト内包表記を使用して、ソートされ、圧縮されたlistから各ペアの最初の要素を抽出します。

一般的なkey関数と同様にsortedパラメータを設定\使用する方法についてのさらなる情報は、 this をご覧ください。


355
Whatang

2つのリストをまとめて圧縮し、並べ替えてから、必要な部分を取り出します。

>>> yx = Zip(Y, X)
>>> yx
[(0, 'a'), (1, 'b'), (1, 'c'), (0, 'd'), (1, 'e'), (2, 'f'), (2, 'g'), (0, 'h'), (1, 'i')]
>>> yx.sort()
>>> yx
[(0, 'a'), (0, 'd'), (0, 'h'), (1, 'b'), (1, 'c'), (1, 'e'), (1, 'i'), (2, 'f'), (2, 'g')]
>>> x_sorted = [x for y, x in yx]
>>> x_sorted
['a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g']

得るためにこれらを一緒に組み合わせてください:

[x for y, x in sorted(Zip(Y, X))]
95
Ned Batchelder

また、厄介な配列を使用しても構わない場合(または実際には既に厄介な配列を処理している場合...)、これはもう1つの良い解決策です。

people = ['Jim', 'Pam', 'Micheal', 'Dwight']
ages = [27, 25, 4, 9]

import numpy
people = numpy.array(people)
ages = numpy.array(ages)
inds = ages.argsort()
sortedPeople = people[inds]

私はここでそれを見つけました: http://scienceoss.com/sort-one-list-by-another-list/

63
Tom

私にとって最も明白な解決策はkeyキーワードargを使うことです。

>>> X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
>>> Y = [ 0,   1,   1,    0,   1,   2,   2,   0,   1]
>>> keydict = dict(Zip(X, Y))
>>> X.sort(key=keydict.get)
>>> X
['a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g']

次のことを行う場合は、これをワンライナーにすることができます。

>>> X.sort(key=dict(Zip(X, Y)).get)
31
senderle

ソートされたインデックスのリストが好きです。こうすることで、ソースリストと同じ順序で任意のリストを並べ替えることができます。ソートされたインデックスのリストを取得したら、単純なリスト内包表記でうまくいきます。

    X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
    Y = [ 0,   1,   1,    0,   1,   2,   2,   0,   1]

    sorted_y_idx_list = sorted(range(len(Y)),key=lambda x:Y[x])
    Xs = [X[i] for i in sorted_y_idx_list ]

    print( "Xs:", Xs )
    # prints: Xs: ["a", "d", "h", "b", "c", "e", "i", "f", "g"]

ソートされたインデックスリストは、numpy argsort()を使って取得することもできます。

12
1-ijk

いくつかの答えを組み合わせた、もう1つの選択肢。

Zip(*sorted(Zip(Y,X)))[1]

Python3のために働くために:

list(Zip(*sorted(Zip(B,A))))[1]
10
TMC

more_itertools には、反復可能オブジェクトを並列にソートするためのツールがあります。

from more_itertools import sort_together


sort_together([Y, X])[1]
# ('a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g')
6
pylang

Zip、2列目でソート、1列目を返します。

Zip(*sorted(Zip(X,Y), key=operator.itemgetter(1)))[0]
4
riza

実際にここに来たのは、値が一致したリストでリストをソートすることです。

list_a = ['foo', 'bar', 'baz']
list_b = ['baz', 'bar', 'foo']
sorted(list_b, key=lambda x: list_a.index(x))
# ['foo', 'bar', 'baz']
4
nackjicholson

素早いワンライナー。

list_a = [5,4,3,2,1]
list_b = [1,1.5,1.75,2,3,3.5,3.75,4,5]

リストaをリストbに一致させるとします。

orderedList =  sorted(list_a, key=lambda x: list_b.index(x))

小さいリストを大きい値に並べ替える必要がある場合に便利です。大きい方のリストに小さい方のリスト内のすべての値が含まれていると仮定すれば、実行できます。

2
Evan Lalo

@ Whatangの答えにヒントを得て、もっと一般的な関数を作成しました。これは、2つ以上のリストを別のリストに基づいてソートするものです。

def parallel_sort(*lists):
    """
    Sorts the given lists, based on the first one.
    :param lists: lists to be sorted

    :return: a Tuple containing the sorted lists
    """

    # Create the initially empty lists to later store the sorted items
    sorted_lists = Tuple([] for _ in range(len(lists)))

    # Unpack the lists, sort them, Zip them and iterate over them
    for t in sorted(Zip(*lists)):
        # list items are now sorted based on the first list
        for i, item in enumerate(t):    # for each item...
            sorted_lists[i].append(item)  # ...store it in the appropriate list

    return sorted_lists
1
pgmank

一次リストをdataとして、他のリストをindexとして使ってpandas Seriesを作成し、インデックスでソートするだけです。

import pandas as pd
pd.Series(data=X,index=Y).sort_index().tolist()

出力:

['a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g']
1
Binyamin Even

両方のソートされたリストを入手したい場合は、Whatangsがこれに答えます(python3)。

X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
Y = [ 0,   1,   1,    0,   1,   2,   2,   0,   1]

Zx, Zy = Zip(*[(x, y) for x, y in sorted(Zip(Y, X))])

print(list(Zx))  # [0, 0, 0, 1, 1, 1, 1, 2, 2]
print(list(Zy))  # ['a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g']

ZxとZyはタプルであることを忘れないでください。私はそれをするよりよい方法があるかどうかも放浪しています。

警告:空のリストで実行するとクラッシュします。

0
Anoroah
list1 = ['a','b','c','d','e','f','g','h','i']
list2 = [0,1,1,0,1,2,2,0,1]

output=[]
cur_loclist = []

list2に存在する一意の値を取得する

list_set = set(list2)

list2でインデックスの場所を見つけるには

list_str = ''.join(str(s) for s in list2)

list2内のインデックスの位置はcur_loclistを使用して追跡されます

[0、3、7、1、2、4、8、5、6]

for i in list_set:
cur_loc = list_str.find(str(i))

while cur_loc >= 0:
    cur_loclist.append(cur_loc)
    cur_loc = list_str.find(str(i),cur_loc+1)

print(cur_loclist)

for i in range(0,len(cur_loclist)):
output.append(list1[cur_loclist[i]])
print(output)
0
VANI