दो सूचियों को कैसे सॉर्ट करें (जो एक दूसरे को संदर्भित करते हैं) ठीक उसी तरह से


139

कह दो मेरी सूची है:

list1 = [3, 2, 4, 1, 1]
list2 = ['three', 'two', 'four', 'one', 'one2']

अगर मैं दौड़ता हूं list1.sort(), तो वह इसे छांट लेगा, [1,1,2,3,4]लेकिन क्या list2सिंक में भी जाने का कोई तरीका है (इसलिए मैं कह सकता हूं कि आइटम 4संबंधित है 'three')? तो, अपेक्षित उत्पादन होगा:

list1 = [1, 1, 2, 3, 4]
list2 = ['one', 'one2', 'two', 'three', 'four']

मेरी समस्या यह है कि मेरे पास एक बहुत ही जटिल कार्यक्रम है जो सूचियों के साथ ठीक काम कर रहा है लेकिन मुझे कुछ डेटा को संदर्भित करने की आवश्यकता है। मुझे पता है कि यह शब्दकोशों के लिए एक आदर्श स्थिति है, लेकिन मैं अपने प्रसंस्करण में शब्दकोशों से बचने की कोशिश कर रहा हूं, क्योंकि मुझे प्रमुख मूल्यों को क्रमबद्ध करने की आवश्यकता है (यदि मुझे शब्दकोशों का उपयोग करना चाहिए तो मुझे पता है कि उनका उपयोग कैसे करना है)।

मूल रूप से इस कार्यक्रम की प्रकृति है, डेटा एक यादृच्छिक क्रम में आता है (ऊपर की तरह), मुझे इसे सॉर्ट करने की आवश्यकता है, इसे संसाधित करें और फिर परिणाम भेजें (आदेश कोई फर्क नहीं पड़ता है लेकिन उपयोगकर्ताओं को यह जानने की आवश्यकता है कि कौन सा परिणाम किससे संबंधित है चाभी)। मैंने इसे पहले एक डिक्शनरी में रखने के बारे में सोचा, फिर सूची को एक क्रमबद्ध किया लेकिन मेरे पास वस्तुओं का विभेदीकरण करने का कोई तरीका नहीं होगा उसी मूल्य के साथ यदि ऑर्डर बनाए नहीं रखा जाता है (उपयोगकर्ताओं के परिणामों को संप्रेषित करते समय इसका प्रभाव हो सकता है)। आदर्श रूप में, एक बार जब मुझे सूचियाँ मिलेंगी तो मैं दोनों सूचियों को एक साथ क्रमबद्ध करने का तरीका समझूँगा। क्या यह संभव है?


मुझे यह इंगित करना चाहिए कि सूची 2 में आपके चर सूची 1 में चींटियों को इंगित नहीं करते हैं। उदाहरण के लिए अगर list1 [0] = 9 जैसे मान को बदलें और list2 को देखें, list2 [0] अभी भी 3 होगा। अजगर में पूर्णांक के साथ, यह संदर्भ / पॉइंटर का उपयोग नहीं करता है, यह मान को कॉपी करता है। आप सूची 2 = सूची 1 [:]
राजा

जवाबों:


242

इस समस्या के लिए एक क्लासिक दृष्टिकोण "डेकोरेट, सॉर्ट, अघोषित" मुहावरे का उपयोग करना है, जो विशेष रूप से अजगर के अंतर्निहित zipफ़ंक्शन का उपयोग करके सरल है:

>>> list1 = [3,2,4,1, 1]
>>> list2 = ['three', 'two', 'four', 'one', 'one2']
>>> list1, list2 = zip(*sorted(zip(list1, list2)))
>>> list1
(1, 1, 2, 3, 4)
>>> list2 
('one', 'one2', 'two', 'three', 'four')

ये पाठ्यक्रम अब सूचियाँ नहीं हैं, लेकिन यह आसानी से सुधारा जाता है, अगर यह मायने रखता है:

>>> list1, list2 = (list(t) for t in zip(*sorted(zip(list1, list2))))
>>> list1
[1, 1, 2, 3, 4]
>>> list2
['one', 'one2', 'two', 'three', 'four']

यह ध्यान देने योग्य है कि ऊपर से मरोड़ के लिए गति का त्याग हो सकता है; इन-प्लेस संस्करण, जिसमें 3 पंक्तियाँ होती हैं, छोटी सूचियों के लिए मेरी मशीन पर तेज़ गति से होती है:

>>> %timeit zip(*sorted(zip(list1, list2)))
100000 loops, best of 3: 3.3 us per loop
>>> %timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100000 loops, best of 3: 2.84 us per loop

दूसरी ओर, बड़ी सूचियों के लिए, एक-पंक्ति संस्करण अधिक तेज़ हो सकता है:

>>> %timeit zip(*sorted(zip(list1, list2)))
100 loops, best of 3: 8.09 ms per loop
>>> %timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100 loops, best of 3: 8.51 ms per loop

जैसा कि क्वांटम 7 बताता है, जेएसएफ का सुझाव अभी भी थोड़ा तेज है, लेकिन यह शायद कभी केवल थोड़ा तेज होगा, क्योंकि पायथन आंतरिक रूप से सभी कुंजी-आधारित प्रकारों के लिए बहुत ही डीएसयू मुहावर का उपयोग करता है । यह सिर्फ नंगे धातु के थोड़ा करीब हो रहा है। (यह दिखाता है कि zipदिनचर्या कितनी अच्छी तरह से अनुकूलित है !)

मुझे लगता है कि zipआधारित दृष्टिकोण अधिक लचीला है और थोड़ा अधिक पठनीय है, इसलिए मैं इसे पसंद करता हूं।


6
तीसरी पंक्ति में तारांकन क्या दर्शाता है?
जेफरी

8
उपरोक्त पर विस्तार से *
बताने के लिए

1
जेएफ सेबेस्टियन द्वारा सुझाए गए सॉर्ट किए गए इंडेक्स / मैप प्रतिमान मेरे लिए ज़िप समाधान की तुलना में लगभग 10% तेज है (10000 यादृच्छिक ints की सूची का उपयोग करते हुए):% टाइमिट इंडेक्स = रेंज (लेन (एल 1)); index.sort (कुंजी = एल 1 .__ getitem__); नक्शा (l1 .__ getitem__, index); नक्शा (l2 .__ getitem__, सूचकांक) 100 लूप, सर्वश्रेष्ठ 3: 8.04 एमएस प्रति लूप (बनाम 9.17 एमएस, 9.07 एमएस प्रेषक के समय के लिए)
क्वांटम 7

1
List1 में पहला और दूसरा ज़िप, list2 = zip (* सॉर्ट किया गया (zip (list1, list2))) इस तरह की अलग चीजें करते हैं। * सभी फर्क पड़ता है।
अशु

1
@ आशू, एक अर्थ में, हाँ! लेकिन दूसरे अर्थ में, वे शायद ही अलग हैं। zip(*x)दिलचस्प संपत्ति है कि यह अपने स्वयं के विपरीत है: l = [(1, 2), (3, 4)]; list(zip(*zip(*l))) == lरिटर्न True। यह प्रभावी रूप से एक ट्रांसपोज़न ऑपरेटर है। zip()अपने दम पर बस एक ही ऑपरेटर है, लेकिन मानता है कि आपने इनपुट अनुक्रम मैन्युअल रूप से अनपैक किया है।
प्रेषि

30

आप कुंजी के रूप में मानों का उपयोग करके अनुक्रमित कर सकते हैं:

indexes = range(len(list1))
indexes.sort(key=list1.__getitem__)

क्रमबद्ध सूचियों को क्रमबद्ध करने के लिए:

sorted_list1 = map(list1.__getitem__, indexes)
sorted_list2 = map(list2.__getitem__, indexes)

आपके मामले में आपके पास जोड़े की एकल सूची नहीं होनी चाहिए list1, list2बल्कि:

data = [(3, 'three'), (2, 'two'), (4, 'four'), (1, 'one'), (1, 'one2')]

इसे बनाना आसान है; पायथन में छाँटना आसान है:

data.sort() # sort using a pair as a key

केवल पहले मान के आधार पर छाँटें:

data.sort(key=lambda pair: pair[0])

इसके बारे में ठंडी बात यह है कि मैं इंडेक्स को इधर-उधर रख सकता हूं और अन्य सामान को बाद में छांट सकता हूं, अगर सूची 1 में एक महत्वपूर्ण समन्वय है जो कई अन्य सरणियों को प्रभावित करता है।
EL_DON

3
अनुक्रमित = सूची (श्रेणी (len (list1))) अजगर 3 के लिए
DonQuiKong

@DonQuiKong भी आपको list() आसपास की जरूरत है map()अगर आप पायथन 3 में इस कोड का उपयोग करना चाहते हैं
jfs

या, के बजाय sorted_list1 = list(map(list1.__getitem__, indexes))एक कर सकता है sorted_list1 = [list1[i] for i in indexes]
नाथन

20

जब तक मुझे पता चला मैंने लंबे समय तक प्रेषक द्वारा दिए गए उत्तर का उपयोग किया है np.argsort। यहाँ दिया गया है कि यह कैसे काम करता है।

# idx works on np.array and not lists.
list1 = np.array([3,2,4,1])
list2 = np.array(["three","two","four","one"])
idx   = np.argsort(list1)

list1 = np.array(list1)[idx]
list2 = np.array(list2)[idx]

मुझे यह समाधान अधिक सहज लगता है, और यह वास्तव में अच्छी तरह से काम करता है। परिपूर्णता:

def sorting(l1, l2):
    # l1 and l2 has to be numpy arrays
    idx = np.argsort(l1)
    return l1[idx], l2[idx]

# list1 and list2 are np.arrays here...
%timeit sorting(list1, list2)
100000 loops, best of 3: 3.53 us per loop

# This works best when the lists are NOT np.array
%timeit zip(*sorted(zip(list1, list2)))
100000 loops, best of 3: 2.41 us per loop

# 0.01us better for np.array (I think this is negligible)
%timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100000 loops, best for 3 loops: 1.96 us per loop

हालांकि np.argsortयह सबसे तेज़ नहीं है, मुझे इसका उपयोग करना आसान लगता है।


1
मुझे आपका उदाहरण चलाने में त्रुटि हुई: TypeError: only integer arrays with one element can be converted to an index(पायथन 2.7.6, सुन्न 1.8.2)। इसे ठीक करने के लिए, लिस्ट 1 और लिस्ट 2 को एक समान सारणी घोषित किया जाना चाहिए।
BenB

धन्यवाद। क्या यह मैं फ़ंक्शन में टिप्पणी में नहीं लिख रहा हूं? वैसे भी, मुझे लगता है कि यह मूर्खतापूर्ण है कि आंतरिक रूप np.argsortसे बदलने की कोशिश न करें np.array
डैनियल थैगार्ड एंड्रियासन

मैं पहले कोड स्निपेट का उल्लेख कर रहा था क्योंकि यह लिखित रूप से नहीं चलता है :)
बेनबी

जब वे सुन्न सरणियों को सौंपे जाते हैं तो मैंने सूचियों को परिवर्तित करके इसे सही किया। टिप्पणी के लिए धन्यवाद :)
डैनियल थागार्ड एंड्रियासन

अब वे Numpy सरणियों में दो बार परिवर्तित हो गए हैं;)
BenB

13

श्वार्टजियन परिवर्तन । अंतर्निहित पायथन छँटाई स्थिर है, इसलिए दोनों को 1समस्या नहीं होती है।

>>> l1 = [3, 2, 4, 1, 1]
>>> l2 = ['three', 'two', 'four', 'one', 'second one']
>>> zip(*sorted(zip(l1, l2)))
[(1, 1, 2, 3, 4), ('one', 'second one', 'two', 'three', 'four')]

2
हालाँकि, यदि आपको लगता है कि आपको ऐसा करने की आवश्यकता है, तो आपको डेटा की दो "समानांतर" सूचियों को फिर से विचार करना चाहिए, जैसा कि 2-ट्यूपल्स (जोड़े) की एक सूची रखने के विरोध में ... या शायद वास्तव में एक वर्ग बनाने के लिए भी। ।
कार्ल केनटेल


2

इसे पूरा करने के लिए आप zip()और sort()कार्यों का उपयोग कर सकते हैं :

Python 2.6.5 (r265:79063, Jun 12 2010, 17:07:01)
[GCC 4.3.4 20090804 (release) 1] on cygwin
>>> list1 = [3,2,4,1,1]
>>> list2 = ['three', 'two', 'four', 'one', 'one2']
>>> zipped = zip(list1, list2)
>>> zipped.sort()
>>> slist1 = [i for (i, s) in zipped]
>>> slist1
[1, 1, 2, 3, 4]
>>> slist2 = [s for (i, s) in zipped]
>>> slist2
['one', 'one2', 'two', 'three', 'four']

उम्मीद है की यह मदद करेगा


2

जब तक आप list2 में दो समान मान न हों, आप कुंजी तर्क को सॉर्ट () विधि में उपयोग कर सकते हैं।

कोड नीचे दिया गया है:

sorted(list2, key = lambda x: list1[list2.index(x)]) 

यह list1 में संबंधित मानों के अनुसार list2 को सॉर्ट करता है, लेकिन सुनिश्चित करें कि इसका उपयोग करते समय, list2 में कोई दो मान समान होने का मूल्यांकन नहीं करते हैं क्योंकि list.index () फ़ंक्शन पहले मान देते हैं


क्रमबद्ध कुछ हालत में धीमी है, हालांकि यह काम करता है।
तान्या

2

एक तरीका यह है कि प्रत्येक सूचकांक जहां पहचान को छांटकर जाता है [0,1,2, .. n]

यह किसी भी संख्या में सूचियों के लिए काम करता है।

फिर प्रत्येक आइटम को उसकी स्थिति में ले जाएं। मसाले का उपयोग करना सबसे अच्छा है।

list1 = [3,2,4,1, 1]
list2 = ['three', 'two', 'four', 'one', 'one2']

index = list(range(len(list1)))
print(index)
'[0, 1, 2, 3, 4]'

index.sort(key = list1.__getitem__)
print(index)
'[3, 4, 1, 0, 2]'

list1[:] = [list1[i] for i in index]
list2[:] = [list2[i] for i in index]

print(list1)
print(list2)
'[1, 1, 2, 3, 4]'
"['one', 'one2', 'two', 'three', 'four']"

ध्यान दें कि हमने सूचियों को क्रमबद्ध किए बिना भी इसे पुनरावृत्त किया हो सकता है:

list1_iter = (list1[i] for i in index)

1

यदि आप सुन्न का उपयोग कर रहे हैं तो आप np.argsortक्रमबद्ध सूचकांकों को प्राप्त करने के लिए उपयोग कर सकते हैं और उन सूचकांकों को सूची में लागू कर सकते हैं । यह उस सूची की किसी भी संख्या के लिए काम करता है जिसे आप सॉर्ट करना चाहते हैं।

import numpy as np

arr1 = np.array([4,3,1,32,21])
arr2 = arr1 * 10
sorted_idxs = np.argsort(arr1)

print(sorted_idxs)
>>> array([2, 1, 0, 4, 3])

print(arr1[sorted_idxs])
>>> array([ 1,  3,  4, 21, 32])

print(arr2[sorted_idxs])
>>> array([ 10,  30,  40, 210, 320])

0

एक एल्गोरिदम समाधान:

list1 = [3,2,4,1, 1]
list2 = ['three', 'two', 'four', 'one', 'one2']


lis = [(list1[i], list2[i]) for i in range(len(list1))]
list1.sort()
list2 = [x[1] for i in range(len(list1)) for x in lis if x[0] == i]

आउटपुट: -> आउटपुट की गति: 0.2s

>>>list1
>>>[1, 1, 2, 3, 4]
>>>list2
>>>['one', 'one2', 'two', 'three', 'four']

0

एक स्ट्रिंग सूची के क्रम को बनाए रखने के लिए एक और दृष्टिकोण जब दूसरी सूची के खिलाफ छंटनी इस प्रकार है:

list1 = [3,2,4,1, 1]
list2 = ['three', 'two', 'four', 'one', 'one2']

# sort on list1 while retaining order of string list
sorted_list1 = [y for _,y in sorted(zip(list1,list2),key=lambda x: x[0])]
sorted_list2 = sorted(list1)

print(sorted_list1)
print(sorted_list2)

उत्पादन

['one', 'one2', 'two', 'three', 'four']
[1, 1, 2, 3, 4]

0

मैं खुले jfs के उत्तर का विस्तार करना चाहूंगा , जिसने मेरी समस्या के लिए बहुत काम किया: एक तिहाई, सजी हुई सूची द्वारा दो सूचियों को क्रमबद्ध करना :

हम अपनी सजी हुई सूची किसी भी तरह से बना सकते हैं, लेकिन इस मामले में हम इसे दो मूल सूचियों में से एक के तत्वों से बनाएंगे, जिन्हें हम छाँटना चाहते हैं:

# say we have the following list and we want to sort both by the algorithms name 
# (if we were to sort by the string_list, it would sort by the numerical 
# value in the strings)
string_list = ["0.123 Algo. XYZ", "0.345 Algo. BCD", "0.987 Algo. ABC"]
dict_list = [{"dict_xyz": "XYZ"}, {"dict_bcd": "BCD"}, {"dict_abc": "ABC"}]

# thus we need to create the decorator list, which we can now use to sort
decorated = [text[6:] for text in string_list]  
# decorated list to sort
>>> decorated
['Algo. XYZ', 'Algo. BCD', 'Algo. ABC']

अब हम अपनी दो सूचियों को तीसरे द्वारा क्रमबद्ध करने के लिए jfs के समाधान को लागू कर सकते हैं

# create and sort the list of indices
sorted_indices = list(range(len(string_list)))
sorted_indices.sort(key=decorated.__getitem__)

# map sorted indices to the two, original lists
sorted_stringList = list(map(string_list.__getitem__, sorted_indices))
sorted_dictList = list(map(dict_list.__getitem__, sorted_indices))

# output
>>> sorted_stringList
['0.987 Algo. ABC', '0.345 Algo. BCD', '0.123 Algo. XYZ']
>>> sorted_dictList
[{'dict_abc': 'ABC'}, {'dict_bcd': 'BCD'}, {'dict_xyz': 'XYZ'}]

संपादित करें: अरे दोस्तों मैंने इस बारे में एक ब्लॉक पोस्ट बनाया है, इसे बाहर की जाँच करें अगर आपको ऐसा लगता है :) guys


-1
newsource=[];newtarget=[]
for valueT in targetFiles:
    for valueS in sourceFiles:
            l1=len(valueS);l2=len(valueT);
            j=0
            while (j< l1):
                    if (str(valueT) == valueS[j:l1]) :
                            newsource.append(valueS)
                            newtarget.append(valueT)
                    j+=1

2
स्पष्टीकरण की कुछ पंक्तियाँ मददगार
होंगी

@saiedmomen I ने इसे stackoverflow.com/questions/53829160/… के संदर्भ में पोस्ट किया है। यहाँ स्रोत स्ट्रिंग पर लक्ष्य स्ट्रिंग की खोज की गई है।
user10340258
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.