Liste başka bir listedeki değerlere göre mi sıralanıyor?


369

Bunun gibi dizelerin bir listesi var:

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

Aşağıdaki çıktıyı elde etmek için X'i Y'den alınan değerleri kullanarak sıralamanın en kısa yolu nedir?

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

Aynı "anahtara" sahip elemanların sırası önemli değildir. forYapıların kullanımına başvurabilirim ama daha kısa bir yol olup olmadığını merak ediyorum. Herhangi bir öneri?


Riza'nın cevabı veri çizilirken yararlı olabilir, çünkü zip (* sıralı (zip (X, Y), anahtar = lambda çifti: çift [0])) X ile Y arasında sıralanan X ve Y değerlerini döndürür.
jojo

Yanıtlar:


479

En Kısa Kod

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

Misal:

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"]

Genel konuşma

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

Açıklaması:

  1. zipiki lists.
  2. yeni, oluşturmak listdayalı sıralama zipoluşturun sorted().
  3. bir liste kavrama kullanarak sıralanmış, sıkıştırılmış her çiftin ilk unsurları ayıklayınlist .

Sete \ kullanma konusunda daha fazla bilgi için keyhem de parametre sortedgenel olarak işlev bakmak bu .



117
Bu doğrudur, ancak aynı diziye göre birden fazla diziyi sıralamaya çalışıyorsanız, sıralamak için kullanılan anahtar (y, x) olduğu için bu gerekli şekilde beklendiği gibi çalışmadığını unutmayın. , sadece y değil. Bunun yerine [x (y, x) için sıralanmış (zip (Y, X), anahtar = lambda çifti: çift [0])]
gms7777

1
güzel çözüm! Ancak şöyle olmalıdır: Liste, çiftlerin ilk elemanı ile ilgili olarak sıralanır ve kavrama çiftlerin 'ikinci' öğesini çıkarır.
MasterControlProgram

Depolama söz konusu olduğunda bu çözüm zayıftır. Mümkün olduğunca yerinde bir sıralama tercih edilir.
19'da Hatefiend

107

İki listeyi birlikte sıkıştırın, sıralayın ve ardından istediğiniz parçaları alın:

>>> 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']

Aşağıdakileri elde etmek için bunları birleştirin:

[x for y, x in sorted(zip(Y, X))]

1
Bu Xbir liste ise iyi str, ancak <bazı öğeler için tanımlanmamış bir olasılık varsa dikkatli olun X, örneğin - eğer bazıları olsaydıNone
John La Rooy

1
Bir zip nesnesi üzerinde sıralama kullanmaya çalıştığımızda, AttributeError: 'zip' object has no attribute 'sort'şu an elde ettiğim şey bu.
Ash Upadhyay

2
Python 3 kullanıyorsunuz. Python 2'de zip bir liste oluşturdu. Şimdi tekrarlanabilir bir nesne üretiyor. sorted(zip(...))hala çalışmalı veya: them = list(zip(...)); them.sort()
Ned Batchelder

77

Ayrıca, numpy dizileri kullanmayı düşünmezseniz (veya aslında zaten numpy dizileriyle uğraşıyorsanız ...), işte başka bir güzel çözüm:

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]

Burada buldum: http://scienceoss.com/sort-one-list-by-another-list/


1
Daha büyük diziler / vektörler için numpy içeren bu çözüm faydalıdır!
MasterControlProgram

1
Zaten numpy dizilerse, o zaman basittir sortedArray1= array1[array2.argsort()]. Ve bu aynı zamanda birden fazla listeyi 2B dizinin belirli bir sütununa göre sıralamayı kolaylaştırır: örneğin sortedArray1= array1[array2[:,2].argsort()], dizi1'i (birden çok sütuna sahip olabilir) dizi2'nin üçüncü sütunundaki değerlere göre sıralamak.
Aaron Bramson

40

Benim için en belirgin çözüm keyarg anahtar sözcüğünü kullanmaktır .

>>> 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']

Aşağıdakileri önemsiyorsanız bunu bir astarla kısaltabileceğinizi unutmayın:

>>> X.sort(key=dict(zip(X, Y)).get)

2
Bu, X'deki değerlerin benzersiz olmasını gerektiriyor mu?
Jack Peng

15

Aslında buraya bir listeyi değerlerin eşleştiği bir listeye göre sıralamak için geldim.

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

1
Bu performans mı?
AFP_555

İpucu yok. Bulduklarınızı geri bildirin.
nackjicholson

1
Bu kötü bir fikir. indexBir gerçekleştirecek O (N) ile arama list_abir sonuçlanan O(N² log N)tür.
Richard

Teşekkürler, performans önemli olduğunda bunu yapmayın!
nackjicholson

15

more_itertools yinelenebilirleri paralel olarak sıralamak için bir araca sahiptir:

verilmiş

from more_itertools import sort_together


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

gösteri

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

13

Sıralı endekslerin bir listesini almayı seviyorum. Bu şekilde, herhangi bir listeyi kaynak listesiyle aynı sırada sıralayabilirim. Sıralanmış endekslerin bir listesine sahip olduğunuzda, basit bir liste kavraması işinizi görecektir:

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"]

Sıralanan dizin listesinin de kullanılabileceğini unutmayın numpy.argsort().


12

Başka bir alternatif, birkaç cevabı birleştiriyor.

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

Python3 ile çalışmak için:

list(zip(*sorted(zip(B,A))))[1]

7

zip, ikinci sütuna göre sıralayın, ilk sütunu döndürün.

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

Not: anahtar = operator.itemgetter (1) yinelenen sorunu çözer
Keith

zip abone değil ... aslında kullanmalısınızlist(zip(*sorted(zip(X,Y), key=operator.itemgetter(1))))[0]
raphael

@ Yinelenen sorun nedir?
Josh

Birden fazla eşleşen varsa ilk alır
Keith

3

Hızlı bir astar.

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

A listesini eşleştirmek istediğinizi varsayalım b.

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

Bu, daha büyük değerlere daha küçük bir liste sipariş etmeniz gerektiğinde yardımcı olur. Daha büyük listenin daha küçük listedeki tüm değerleri içerdiği varsayılarak, yapılabilir.


Bu OP'nin sorusunu çözmez. Eğer örnek listeleri ile denediniz mi Xve Y?
Aryeh Leib Taurog

Bu kötü bir fikir. indexBir gerçekleştirecek O (N) ile arama list_bbir sonuçlanan O(N² log N)tür.
Richard

1

pandas SeriesBirincil listeyi datave diğer listeyi kullanarak bir a oluşturabilir indexve ardından dizine göre sıralayabilirsiniz:

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

çıktı:

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

1

Her iki sıralı listeyi (python3) almak istiyorsanız Whatangs cevabı.

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 ve Zy'nin tuple olduğunu hatırlayın. Bunu yapmanın daha iyi bir yolu varsa da dolaşıyorum.

Uyarı: Boş listelerle çalıştırırsanız kilitlenir.


1

@ Whatang'ın cevabından esinlenerek başka bir listeye dayanan ikiden fazla listeyi sıralayan daha genel bir işlev oluşturdum.

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

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

output=[]
cur_loclist = []

Benzersiz değerleri sunmak için list2

list_set = set(list2)

İçindeki dizinin yerini bulmak için list2

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

İçindeki dizinin yeri list2kullanılarak izlenircur_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

Bu eski bir soru ama yayınladığım bazı cevaplar aslında çalışmıyor çünkü zipyazılabilir değil. Diğer cevaplar rahatsız olmadıimport operator bu modül ve faydaları hakkında daha fazla bilgi .

Bu sorun için en az iki iyi deyim vardır. Girdiğiniz örnek girişten başlayarak:

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

" Decorate-Sort-Udecorate " deyimini kullanma

Bu, 90'larda Perl'de bu modeli popülerleştiren R. Schwartz'ın ardından Schwartzian_transform olarak da bilinir :

# Zip (decorate), sort and unzip (undecorate).
# Converting to list to script the output and extract X
list(zip(*(sorted(zip(Y,X)))))[1]                                                                                                                       
# Results in: ('a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g')

Bu durumda Yve Xsözlükbilimsel olarak sıralandığını ve karşılaştırıldığını unutmayın. Yani, ilk maddeler (itibaren Y) karşılaştırılır; ve eğer bunlar aynıysa, ikinci maddeler (from X) karşılaştırılır, vb. Yinelenenleri orijinal sıralarında tutmak için sözlükbilimsel sıralamaya ilişkin orijinal liste indekslerini dahil etmedikçe bu, kararsız çıktılar oluşturabilir .

Modülü kullanmaoperator

Bu, girişin nasıl sıralanacağı üzerinde daha doğrudan kontrol sağlar, böylece sıralamak için belirli bir anahtarı belirterek sıralama kararlılığı elde edebilirsiniz . Daha fazla örneği burada görebilirsiniz .

import operator    

# Sort by Y (1) and extract X [0]
list(zip(*sorted(zip(X,Y), key=operator.itemgetter(1))))[0]                                                                                                 
# Results in: ('a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.