सूची को सेट परिवर्तन तत्व क्रम में परिवर्तित करना


119

हाल ही में मैंने देखा है कि जब मैं एक परिवर्तित कर रहा हूँ listकरने के लिए setतत्वों का क्रम बदल जाता है और चरित्र के अनुसार क्रमबद्ध किया गया है।

इस उदाहरण पर विचार करें:

x=[1,2,20,6,210]
print x 
# [1, 2, 20, 6, 210] # the order is same as initial order

set(x)
# set([1, 2, 20, 210, 6]) # in the set(x) output order is sorted

मेरे प्रश्न हैं -

  1. ये क्यों हो रहा है?
  2. प्रारंभिक आदेश को खोए बिना मैं ऑपरेशन (विशेष रूप से सेट अंतर) कैसे सेट कर सकता हूं?

8
आप प्रारंभिक आदेश क्यों नहीं खोना चाहते, खासकर यदि आप सेट ऑपरेशन कर रहे हैं? "ऑर्डर" न केवल पाइथन में बल्कि गणित में सेट के लिए एक अर्थहीन अवधारणा है।
कार्ल केनचेल

131
@KarlKnechtel - हाँ "आदेश सेट के लिए एक अर्थहीन अवधारणा है ... गणित में" लेकिन मुझे वास्तविक दुनिया की समस्याएं हैं :)
d.putto

CPython 3.6+ पर unique = list(dict.fromkeys([1, 2, 1]).keys())। यह काम करता है क्योंकि dictअब सम्मिलन क्रम संरक्षित है।
बोरिस

जवाबों:


106
  1. setएक अनियंत्रित डेटा संरचना है, इसलिए यह सम्मिलन क्रम को संरक्षित नहीं करता है।

  2. यह आपकी आवश्यकताओं पर निर्भर करता है। यदि आपके पास एक सामान्य सूची है, और सूची के क्रम को संरक्षित करते हुए तत्वों के कुछ सेट को हटाना चाहते हैं, तो आप ऐसा सूची विवरण के साथ कर सकते हैं:

    >>> a = [1, 2, 20, 6, 210]
    >>> b = set([6, 20, 1])
    >>> [x for x in a if x not in b]
    [2, 210]

    यदि आपको एक डेटा संरचना की आवश्यकता होती है जो तेजी से सदस्यता परीक्षणों और सम्मिलन क्रम के संरक्षण दोनों का समर्थन करती है , तो आप पायथन डिक्शनरी की कुंजियों का उपयोग कर सकते हैं, जो पायथन 3.7 से शुरू होकर प्रविष्टि क्रम को संरक्षित करने की गारंटी है:

    >>> a = dict.fromkeys([1, 2, 20, 6, 210])
    >>> b = dict.fromkeys([6, 20, 1])
    >>> dict.fromkeys(x for x in a if x not in b)
    {2: None, 210: None}

    bवास्तव में यहां ऑर्डर करने की आवश्यकता नहीं है - आप एक setअच्छी तरह से उपयोग कर सकते हैं । ध्यान दें कि a.keys() - b.keys()सेट अंतर को एक के रूप में लौटाता है set, इसलिए यह प्रविष्टि क्रम को संरक्षित नहीं करेगा।

    पायथन के पुराने संस्करणों में, आप collections.OrderedDictइसके बजाय उपयोग कर सकते हैं :

    >>> a = collections.OrderedDict.fromkeys([1, 2, 20, 6, 210])
    >>> b = collections.OrderedDict.fromkeys([6, 20, 1])
    >>> collections.OrderedDict.fromkeys(x for x in a if x not in b)
    OrderedDict([(2, None), (210, None)])

3
किसी भी वस्तु की लागत 16 बाइट नहीं होती है। यदि केवल एक डिफ़ॉल्ट आर्डरसेट () है। :(
शॉन

2
@ सीन नहीं, वे नहीं। Noneएक भाषा की गारंटी है सिंगलटन। CPython में, एक वास्तविक लागत सिर्फ पॉइंटर है (हालाँकि वह लागत हमेशा होती है, लेकिन एक तानाशाही के लिए, आप लगभग Noneसिंगल सिंगल्स या अन्य संदर्भों पर विचार कर सकते हैं या साझा संदर्भ "फ्री"), इसलिए एक मशीन शब्द, आधुनिक कंप्यूटरों पर 8 बाइट्स की संभावना है । लेकिन हाँ, यह उतना कुशल नहीं है जितना एक सेट हो सकता है।
juanpa.arrivillaga

2
CPython 3.6+ पर आप सिर्फ dict.fromkeys([1, 2, 1]).keys()इसलिए कर सकते हैं क्योंकि नियमित रूप से dictऑर्डर को संरक्षित करते हैं।
बोरिस

@ बोरिस यह केवल पायथन 3.7 से शुरू होने वाले भाषा विनिर्देश का हिस्सा रहा है। जबकि सीपीथॉन कार्यान्वयन पहले से ही संस्करण 3.6 में सम्मिलन आदेश को संरक्षित करता है, यह एक कार्यान्वयन विवरण माना जाता है जिसे अन्य पायथन कार्यान्वयन द्वारा पालन नहीं किया जा सकता है।
स्वेन मार्नाच

@ मैंने कहा कि सीपीथॉन। मैं इसे हर जगह पोस्ट करता हूं, मैं बस "सीपीथॉन 3.6 या पायथन 3.7 के साथ शुरू होने वाले किसी भी अन्य कार्यान्वयन" को लिखकर थक गया हूं। इससे कोई फर्क नहीं पड़ता, हर कोई CPython का उपयोग कर रहा है
बोरिस

52

अजगर 3.6 में, set()अब आदेश रखना चाहिए , लेकिन पायथन 2 और 3 के लिए एक और उपाय है:

>>> x = [1, 2, 20, 6, 210]
>>> sorted(set(x), key=x.index)
[1, 2, 20, 6, 210]

8
आदेश संरक्षण के संबंध में दो नोट: केवल पायथन 3.6 के रूप में, और वहां भी, इसे कार्यान्वयन विवरण माना जाता है, इसलिए इस पर भरोसा न करें। इसके अलावा, आपका कोड बहुत अक्षम है क्योंकि हर बार x.indexकॉल करने पर, एक रैखिक खोज की जाती है। यदि आप द्विघात जटिलता के साथ ठीक हैं, setतो पहली जगह में उपयोग करने का कोई कारण नहीं है।
थाइज वैन दीन

27
@ThijsvanDien यह गलत है, set()पायथन 3.6, यहां तक कि नहीं एक कार्यान्वयन विस्तार के रूप में, आप के बारे में सोच में आदेश दिया नहीं है dictरों
Chris_Rands

8
@ThijsvanDien नहीं, वे क्रमबद्ध नहीं हैं, हालांकि कभी-कभी ऐसा दिखाई देता है क्योंकि intअक्सर खुद को stackoverflow.com/questions/45581901/… है
Chris_Rands

3
कोशिश करो x=[1,2,-1,20,6,210]और इसे एक सेट बनाओ। आप देखेंगे कि यह Python 3.6 में परीक्षण किया गया है।
गेब्रियलचू

3
मुझे समझ नहीं आ रहा है कि इस उत्तर में इतने सारे बदलाव क्यों हैं, यह प्रविष्टि आदेश नहीं रखता है, न ही एक सेट लौटाता है।
इगोर रोड्रिगेज

20

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


9

डुप्लिकेट को हटा दें और नीचे दिए गए फ़ंक्शन द्वारा ऑर्डर संरक्षित करें

def unique(sequence):
    seen = set()
    return [x for x in sequence if not (x in seen or seen.add(x))]

इस लिंक की जाँच करें


एक अच्छा तरीका, मेरे समाधान से बेहतर है :)
टाइगर -222

8

गणित में, सेट और ऑर्डर किए गए सेट (ओसेट) हैं।

  • सेट : अद्वितीय तत्वों का एक अनियंत्रित कंटेनर (कार्यान्वित)
  • ओसेट : अनूठे तत्वों का एक ऑर्डर किया हुआ कंटेनर (NotImplemented)

पायथन में, केवल सेट को सीधे लागू किया जाता है। हम नियमित रूप से निर्धारित कुंजियों ( 3.7+ ) के साथ ओसेट्स का अनुकरण कर सकते हैं ।

दिया हुआ

a = [1, 2, 20, 6, 210, 2, 1]
b = {2, 6}

कोड

oset = dict.fromkeys(a).keys()
# dict_keys([1, 2, 20, 6, 210])

डेमो

प्रतिकृतियां हटा दी जाती हैं, सम्मिलन-क्रम संरक्षित होता है।

list(oset)
# [1, 2, 20, 6, 210]

तानाशाह की चाबियों पर सेट जैसे ऑपरेशन।

oset - b
# {1, 20, 210}

oset | b
# {1, 2, 5, 6, 20, 210}

oset & b
# {2, 6}

oset ^ b
# {1, 5, 20, 210}

विवरण

ध्यान दें: एक अनियंत्रित संरचना आदेशित तत्वों को नहीं छोड़ती है। बल्कि, बनाए रखा आदेश की गारंटी नहीं है। उदाहरण:

assert {1, 2, 3} == {2, 3, 1}                    # sets (order is ignored)

assert [1, 2, 3] != [2, 3, 1]                    # lists (order is guaranteed)

यह जानकर प्रसन्नता हो सकती है कि एक सूची और मल्टीसेट (mset) दो और आकर्षक, गणितीय डेटा संरचनाएँ हैं:

  • सूची : प्रतिकृति के लिए अनुमति देने वाले तत्वों का एक आदेशित कंटेनर (कार्यान्वित)
  • mset : तत्वों का एक अनियंत्रित कंटेनर जो प्रतिकृति की अनुमति देता है (NotImplemented) *

सारांश

Container | Ordered | Unique | Implemented
----------|---------|--------|------------
set       |    n    |    y   |     y
oset      |    y    |    y   |     n
list      |    y    |    n   |     y
mset      |    n    |    n   |     n*  

* एक मल्टीसेट परोक्ष रूप से साथ नकल करते किया जा सकता है collections.Counter(), की मैपिंग dict की तरह multiplicities (मायने रखता है)।


4

जैसा कि अन्य उत्तरों में दर्शाया गया है, सेट डेटा संरचना (और गणितीय अवधारणाएं) हैं जो तत्व क्रम को संरक्षित नहीं करते हैं -

हालांकि, सेट और शब्दकोशों के संयोजन का उपयोग करके, यह संभव है कि आप जो भी वांछित हो, प्राप्त कर सकते हैं - इन स्निपेट का उपयोग करके देखें:

# save the element order in a dict:
x_dict = dict(x,y for y, x in enumerate(my_list) )
x_set = set(my_list)
#perform desired set operations
...
#retrieve ordered list from the set:
new_list = [None] * len(new_set)
for element in new_set:
   new_list[x_dict[element]] = element

1

स्वेन के उत्तर पर निर्माण, मैंने संग्रह का उपयोग करते हुए पाया।अनुकूलित जैसे निर्णय ने मुझे यह पूरा करने में मदद की कि आप क्या चाहते हैं और साथ ही मुझे अधिक वस्तुओं को जोड़ने की अनुमति दें:

import collections

x=[1,2,20,6,210]
z=collections.OrderedDict.fromkeys(x)
z
OrderedDict([(1, None), (2, None), (20, None), (6, None), (210, None)])

यदि आप आइटम जोड़ना चाहते हैं, लेकिन फिर भी इसे एक ऐसे सेट की तरह मानें जो आप बस कर सकते हैं:

z['nextitem']=None

और आप ताना पर z.keys () की तरह एक ऑपरेशन कर सकते हैं और सेट प्राप्त कर सकते हैं:

z.keys()
[1, 2, 20, 6, 210]

आपको list(z.keys())सूची आउटपुट प्राप्त करने के लिए करने की आवश्यकता है ।
jxn

पायथन 3 में, हाँ। पाइथन 2 में नहीं, हालांकि मुझे निर्दिष्ट करना चाहिए था।
जिम्ह

0

ऊपर उच्चतम स्कोर अवधारणा का कार्यान्वयन जो इसे एक सूची में वापस लाता है:

def SetOfListInOrder(incominglist):
    from collections import OrderedDict
    outtemp = OrderedDict()
    for item in incominglist:
        outtemp[item] = None
    return(list(outtemp))

पायथन 3.6 और पायथन 2.7 पर परीक्षण (संक्षेप में)।


0

यदि आपके पास अपनी दो प्रारंभिक सूचियों में कम संख्या में तत्व हैं, जिस पर आप अंतर ऑपरेशन करना चाहते हैं, collections.OrderedDictजिसके बजाय कार्यान्वयन को जटिल बनाता है और इसे कम पठनीय बनाता है, तो आप उपयोग कर सकते हैं:

# initial lists on which you want to do set difference
>>> nums = [1,2,2,3,3,4,4,5]
>>> evens = [2,4,4,6]
>>> evens_set = set(evens)
>>> result = []
>>> for n in nums:
...   if not n in evens_set and not n in result:
...     result.append(n)
... 
>>> result
[1, 3, 5]

इसकी समय जटिलता इतनी अच्छी नहीं है लेकिन यह साफ और पढ़ने में आसान है।


0

यह दिलचस्प है कि सैद्धांतिक विज्ञान में परिभाषा पर मजाक बनाने के लिए लोग हमेशा 'वास्तविक दुनिया की समस्या' का उपयोग करते हैं।

यदि सेट में आदेश है, तो आपको पहले निम्नलिखित समस्याओं का पता लगाने की आवश्यकता है। यदि आपकी सूची में डुप्लिकेट तत्व हैं, तो जब आप इसे एक सेट में बदलते हैं तो क्या क्रम होना चाहिए? यदि हम दो सेट करते हैं तो क्या होगा? यदि हम एक ही तत्वों पर अलग-अलग क्रम से दो सेटों को काटते हैं तो क्या होगा?

इसके अलावा, सेट एक विशेष कुंजी की खोज में बहुत तेज है जो सेट ऑपरेशन में बहुत अच्छा है (और इसीलिए आपको सेट की आवश्यकता है, लेकिन सूची नहीं)।

यदि आप वास्तव में सूचकांक की परवाह करते हैं, तो इसे एक सूची के रूप में रखें। यदि आप अभी भी कई सूचियों में तत्वों पर सेट ऑपरेशन करना चाहते हैं, तो सरल तरीका मूल सूची में कुंजी के सभी सूचकांक वाले सूची के मूल्य के साथ सेट में समान कुंजी के साथ प्रत्येक सूची के लिए एक शब्दकोश बना रहा है।

def indx_dic(l):
    dic = {}
    for i in range(len(l)):
        if l[i] in dic:
            dic.get(l[i]).append(i)
        else:
            dic[l[i]] = [i]
    return(dic)

a = [1,2,3,4,5,1,3,2]
set_a  = set(a)
dic_a = indx_dic(a)

print(dic_a)
# {1: [0, 5], 2: [1, 7], 3: [2, 6], 4: [3], 5: [4]}
print(set_a)
# {1, 2, 3, 4, 5}

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