किसी अन्य सूची से मानों के आधार पर छंटनी सूची?


369

मेरे पास इस तरह के तार की एक सूची है:

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

निम्नलिखित आउटपुट प्राप्त करने के लिए Y से मूल्यों का उपयोग करके एक्स को सॉर्ट करने का सबसे छोटा तरीका क्या है?

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

समान "कुंजी" वाले तत्वों का क्रम मायने नहीं रखता है। मैं forनिर्माणों के उपयोग का सहारा ले सकता हूं लेकिन अगर कोई छोटा रास्ता है तो मैं उत्सुक हूं। कोई सुझाव?


डेटा को प्लॉट करते समय रीज़ा का जवाब उपयोगी हो सकता है, क्योंकि ज़िप (* सॉर्ट (ज़िप (एक्स, वाई), की = लैम्ब्डा जोड़ी: जोड़ी [0])) सॉर्ट किए गए एक्स और वाई दोनों को एक्स के मूल्यों के साथ सॉर्ट करता है
जोजो

जवाबों:


479

सबसे छोटा कोड

[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दो listएस।
  2. उपयोग के listआधार पर एक नया, क्रमबद्ध zipकरें sorted()
  3. एक सूची का उपयोग करके प्रत्येक जोड़े के पहले तत्वों को छांटे गए, ज़िपित से निकालेंlist

keyपैरामीटर के साथ-साथ sortedसामान्य रूप से फ़ंक्शन का उपयोग कैसे करें, इस बारे में अधिक जानकारी के लिए , इस पर एक नज़र डालें ।



117
यह सही है, लेकिन मैं यह नोट जोड़ूंगा कि यदि आप एक ही सरणी द्वारा कई सरणियों को क्रमबद्ध करने की कोशिश कर रहे हैं, तो यह संभवत: अपेक्षित रूप से काम नहीं करेगा, क्योंकि जिस कुंजी को सॉर्ट करने के लिए उपयोग किया जा रहा है वह है (y, x) , सिर्फ y नहीं। आप के बजाय का उपयोग करना चाहिए [हल कर में (y, x) के लिए एक्स (ज़िप (वाई, एक्स), कुंजी = लैम्ब्डा जोड़ी: जोड़ी [0])]
gms7777

1
अच्छा समाधान! लेकिन यह होना चाहिए: सूची को जोड़े के पहले तत्व के बारे में आदेश दिया गया है, और समझ जोड़े का 'दूसरा' तत्व निकालती है।
MasterControlProgram

भंडारण के लिए यह समाधान खराब है। जब भी संभव हो एक इन-प्लेस सॉर्ट पसंद किया जाता है।
हेटफाइंड

107

दो सूचियों को एक साथ जिप करें, इसे क्रमबद्ध करें, फिर अपने इच्छित भागों को लें:

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

1
अगर Xयह एक सूची है str, तो ठीक है , लेकिन सावधान रहें यदि ऐसी कोई संभावना है, जिसमें <कुछ जोड़ी गई वस्तुओं के लिए परिभाषित नहीं किया गया है X, जैसे - यदि उनमें से कुछ थेNone
जॉन ला रोय

1
जब हम एक जिप ऑब्जेक्ट पर सॉर्ट का उपयोग करने की कोशिश करते हैं, AttributeError: 'zip' object has no attribute 'sort'तो वही है जो मुझे अब मिल रहा है।
ऐश उपाध्याय

2
आप पायथन 3 का उपयोग कर रहे हैं। पायथन 2 में, ज़िप ने एक सूची तैयार की। अब यह एक पुनरावृत्त वस्तु का उत्पादन करता है। sorted(zip(...))अभी भी काम करना चाहिए, या: them = list(zip(...)); them.sort()
नेड बैचेल्ड

77

इसके अलावा, अगर आपको अफीम सरणियों का उपयोग करने में कोई आपत्ति नहीं है (या वास्तव में पहले से ही खस्ता सरणियों से निपट रहे हैं ...), तो यहां एक और अच्छा समाधान है:

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/


1
बड़े सरणियों / वैक्टर के लिए, सुन्न के साथ यह समाधान फायदेमंद है!
MasterControlProgram

1
यदि वे पहले से ही सुन्न सरणियाँ हैं, तो यह बस है sortedArray1= array1[array2.argsort()]। और यह एक 2D सरणी के एक विशेष कॉलम द्वारा कई सूचियों को सॉर्ट करना आसान बनाता है: sortedArray1= array1[array2[:,2].argsort()]array2 के तीसरे कॉलम में मानों द्वारा array1 (जिसमें कई कॉलम हो सकते हैं) को सॉर्ट करना।
एरोन ब्रामसन

40

मेरे लिए सबसे स्पष्ट समाधान 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)

2
क्या इसके लिए X में मौजूद मानों का उपयोग नहीं होना चाहिए?
जैक पेंग

15

मैं वास्तव में एक सूची द्वारा सूची को क्रमबद्ध करने के लिए यहां आया था जहां मूल्यों का मिलान हुआ था।

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

1
क्या यह प्रदर्शनकारी है?
AFP_555

कोई सुराग नहीं। आपको जो मिल रहा है, उसे वापस रिपोर्ट करें।
nackjicholson

1
यह विचार अच्छा नहीं है। एक तरह से जिसके परिणामस्वरूप पर indexएक ओ (एन) खोज प्रदर्शन करेंगे । list_aO(N² log N)
रिचर्ड

धन्यवाद, ऐसा तब न करें जब प्रदर्शन मायने रखता है!
nackjicholson

15

more_itertools समानांतर में पुनरावृत्तियों को छाँटने के लिए एक उपकरण है:

दिया हुआ

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]

डेमो

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

13

मुझे छांटे गए सूचकांकों की सूची पसंद है। इस तरह, मैं किसी भी सूची को स्रोत सूची के समान क्रम में सॉर्ट कर सकता हूं। एक बार जब आपके पास सॉर्ट किए गए सूचकांकों की एक सूची होती है, तो एक सरल सूची समझ की चाल चलेगी:

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

एक अन्य विकल्प, कई उत्तरों का संयोजन।

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

Python3 के लिए काम करने के लिए:

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

7

zip, दूसरे कॉलम द्वारा सॉर्ट करें, पहला कॉलम वापस करें।

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

नोट: कुंजी = oper.itemgetter (1) डुप्लिकेट समस्या हल करता है
कीथ

ज़िप सदस्यता योग्य नहीं है ... आपको वास्तव में उपयोग करना होगाlist(zip(*sorted(zip(X,Y), key=operator.itemgetter(1))))[0]
राफेल

@ क्या डुप्लिकेट मुद्दा?
जोश

यदि एक से अधिक मिलान होते हैं तो यह पहला होता है
कीथ

3

एक त्वरित एक लाइनर।

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

कहते हैं कि आप सूची से मैच सूची बी चाहते हैं।

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

बड़े में मूल्यों के लिए एक छोटी सूची का आदेश देने की आवश्यकता होने पर यह सहायक होता है। यह मानते हुए कि बड़ी सूची में छोटी सूची के सभी मूल्य शामिल हैं, यह किया जा सकता है।


इससे ओपी का सवाल हल नहीं होता। क्या आपने इसे नमूना सूचियों के साथ आज़माया Xऔर Y?
आर्येह लीब तौआरोग

यह विचार अच्छा नहीं है। एक तरह से जिसके परिणामस्वरूप पर indexएक ओ (एन) खोज प्रदर्शन करेंगे । list_bO(N² log N)
रिचर्ड

1

आप pandas Seriesप्राथमिक सूची के रूप में dataऔर दूसरी सूची का उपयोग करके एक बना सकते हैं index, और फिर सूचकांक द्वारा क्रमबद्ध करें:

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

उत्पादन:

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

1

यदि आप दोनों क्रमबद्ध सूची (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 टुपल्स हैं। अगर ऐसा करने का कोई बेहतर तरीका है तो मैं भी भटक रहा हूं।

चेतावनी: यदि आप इसे खाली सूचियों के साथ चलाते हैं तो यह क्रैश हो जाता है।


1

मैंने एक और सामान्य फ़ंक्शन बनाया है, जो @ व्हाट्स के उत्तर से प्रेरित होकर, एक के आधार पर दो से अधिक सूचियों को क्रमबद्ध करता है।

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 = []

में मौजूद अद्वितीय मूल्यों को प्राप्त करने के लिए 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

यह एक पुराना प्रश्न है, लेकिन मेरे द्वारा पोस्ट किए गए कुछ उत्तर वास्तव में काम नहीं करते हैं क्योंकि zipयह स्क्रिप्ट करने योग्य नहीं है। अन्य उत्तर परेशान नहीं हुएimport operator इस मॉड्यूल और इसके लाभों के बारे में अधिक जानकारी प्रदान हैं।

इस समस्या के लिए कम से कम दो अच्छे मुहावरे हैं। आपके द्वारा दिए गए उदाहरण इनपुट से शुरू:

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

" डेकोरेट-सॉर्ट-अंडरकोरेट " मुहावरे का उपयोग करना

आर। श्वार्ट्ज के बाद इसे श्वार्टजियन_ट्रांसफॉर्म के रूप में भी जाना जाता है जिन्होंने 90 के दशक में पर्ल में इस पैटर्न को लोकप्रिय बनाया:

# 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')

ध्यान दें कि इस मामले में Yऔर Xक्रमबद्ध हैं और तुलनात्मक रूप से। यही है, पहले आइटम (से Y) की तुलना की जाती है; और यदि वे समान हैं तो दूसरी वस्तुओं (से X) की तुलना की जाती है, और इसी तरह। यह अस्थिर आउटपुट तब तक बना सकता है जब तक कि आप लेक्सोग्राफ़िक ऑर्डर के लिए मूल सूची सूचक को अपने मूल क्रम में डुप्लिकेट रखने के लिए शामिल नहीं करते हैं।

मॉड्यूल का उपयोग करनाoperator

यह आपको इनपुट को क्रमबद्ध करने के तरीके के बारे में अधिक प्रत्यक्ष नियंत्रण प्रदान करता है, जिससे आप केवल क्रमबद्ध करने के लिए विशिष्ट कुंजी को बताकर छँटाई स्थिरता प्राप्त कर सकते हैं । यहाँ और अधिक उदाहरण देखें ।

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')
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.