একটি তালিকাটিকে একটি সেটে রূপান্তর করা উপাদান ক্রমের পরিবর্তন করে


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

সিপিথন 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]

    আপনার যদি এমন ডেটা স্ট্রাকচারের প্রয়োজন হয় যা দ্রুত সদস্যপদ পরীক্ষা এবং সন্নিবেশ ক্রমের সংরক্ষণ উভয় সমর্থন করে , আপনি পাইথন অভিধানের কীগুলি ব্যবহার করতে পারেন, যা পাইথন ৩.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একটি ভাষা গ্যারান্টিযুক্ত সিঙ্গলটন। সিপিথনে প্রকৃত ব্যয়টি কেবলমাত্র পয়েন্টার (যদিও সেই ব্যয়টি সর্বদা থাকে, তবে ডিকের জন্য আপনি প্রায় বিবেচনা করতে পারেন Noneএবং অন্যান্য সিলেটলেট বা ভাগ করা রেফারেন্সগুলি "ফ্রি"), সুতরাং একটি মেশিন শব্দ, আধুনিক কম্পিউটারে সম্ভবত 8 বাইট । তবে হ্যাঁ, এটি কোনও সেট হিসাবে কার্যকর স্থান হিসাবে কার্যকর নয়।
juanpa.arrivillaga

2
সিপিথন ৩.+++ এ আপনি কেবলমাত্র করতে পারেন dict.fromkeys([1, 2, 1]).keys()কারণ নিয়মিত এসগুলিও dictঅর্ডার সংরক্ষণ করে।
বরিস

@ বোরিস এটি পাইথন ৩.7 থেকে শুরু হওয়া ভাষার স্পেসিফিকেশনের অংশ মাত্র। সিপিথন বাস্তবায়ন ইতিমধ্যে সংস্করণ 3.6-এ সন্নিবেশ ক্রম সংরক্ষণ করেছে, এটি একটি বাস্তবায়ন বিশদ হিসাবে বিবেচিত যা অন্য পাইথন বাস্তবায়ন দ্বারা অনুসরণ করা নাও যেতে পারে।
সোভেন মারনাচ

@ সপ্তন আমি সিপিথন বলেছি। আমি সর্বত্র এটি পোস্ট করি, আমি "সিপিথন 3.6 বা পাইথন 3.7 দিয়ে শুরু করে অন্য কোনও প্রয়োগ" লিখে ক্লান্ত হয়ে পড়ছি। এমনকি এটি কোনও ব্যাপার নয়, প্রত্যেকে সিপিথন ব্যবহার করছে
বোরিস

52

পাইথন ৩.6-তে, set()এখন অর্ডারটি রাখা উচিত , তবে পাইথন 2 এবং 3 এর জন্য আরও একটি সমাধান রয়েছে:

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

8
অর্ডার সংরক্ষণ সম্পর্কিত দুটি নোট: কেবল পাইথন ৩.6 হিসাবে এবং সেখানেও এটি একটি প্রয়োগের বিশদ হিসাবে বিবেচনা করা হয়, সুতরাং এটির উপর নির্ভর করবেন না। এগুলি ছাড়াও, আপনার কোডটি খুব অকার্যকর কারণ প্রতিবার যখন x.indexবলা হয় তখন একটি লিনিয়ার অনুসন্ধান করা হয়। আপনি যদি চতুষ্কোণ জটিলতার সাথে ভাল setথাকেন তবে প্রথমে একটি ব্যবহার করার কোনও কারণ নেই ।
থিজ ভ্যান ডিয়েন

27
@ থিজসওয়ানডিয়েন এটি ভুল, set()পাইথন ৩. 3. এ অর্ডার করা হয়নি, এমনকি বাস্তবায়নের বিবরণ হিসাবেও নয়, আপনি dictএস এর কথা ভাবছেন
ক্রিস_আর্যান্ডস

8
@ThijsvanDien কোন তারা সাজানো করছি না যদিও কখনও কখনও তাই প্রদর্শিত কারণ intগুলি প্রায়ই নিজেদের হ্যাশ stackoverflow.com/questions/45581901/...
Chris_Rands

3
চেষ্টা করুন x=[1,2,-1,20,6,210]এবং এটি একটি সেট করুন। আপনি দেখতে পাবেন এটি একেবারেই অর্ডার করা হয়নি, পাইথন ৩.6 এ পরীক্ষিত।
গ্যাব্রিয়েলচু

3
আমি বুঝতে পারি না কেন এই উত্তরে এতগুলি উত্সাহ রয়েছে, এটি সন্নিবেশ ক্রম রাখে না, সেটও দেয় না।
ইগোর রদ্রিগেজ

20

আপনার প্রথম প্রশ্নের জবাব দেওয়া, একটি সেট সেট অপারেশনগুলির জন্য অনুকূল একটি ডেটা স্ট্রাকচার। গাণিতিক সেটের মতো এটি উপাদানগুলির কোনও নির্দিষ্ট ক্রম প্রয়োগ করে বা বজায় রাখে না। কোনও সেটটির বিমূর্ত ধারণাটি অর্ডার প্রয়োগ করে না, তাই বাস্তবায়নের প্রয়োজন হয় না। আপনি যখন একটি তালিকা থেকে একটি সেট তৈরি করেন, পাইথনের অভ্যন্তরীণ বাস্তবায়নের প্রয়োজনীয়তার জন্য উপাদানগুলির ক্রম পরিবর্তন করার স্বাধীনতা রয়েছে যা এটি কোনও সেটের জন্য ব্যবহার করে, যা দক্ষতার সাথে সেট ক্রিয়াকলাপ সম্পাদন করতে সক্ষম।


9

সদৃশগুলি মুছে ফেলুন এবং নীচের ফাংশন দ্বারা অর্ডার সংরক্ষণ করুন

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

এই লিঙ্কটি পরীক্ষা করুন


খুব সুন্দর, আমার সমাধানের চেয়ে ভাল উপায় :)
টাইগার -২২২

8

গণিতে, সেট এবং অর্ডার করা সেট (ওসেটস) রয়েছে।

  • সেট : অনন্য উপাদানগুলির একটি আনর্ডার্ড পাত্রে (কার্যকর)
  • ওসেট : অনন্য উপাদানগুলির একটি অর্ডারযুক্ত ধারক (নয় বাস্তবায়নযোগ্য)

পাইথনে, কেবল সেটগুলি সরাসরি প্রয়োগ করা হয়। আমরা নিয়মিত ডিক কী ( 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}

বিস্তারিত

দ্রষ্টব্য: একটি অর্ডারযুক্ত কাঠামো আদেশকৃত উপাদানগুলিকে বাদ দেয় না। বরং রক্ষণাবেক্ষণ আদেশের নিশ্চয়তা নেই not উদাহরণ:

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

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

কেউ আবিষ্কার করে সন্তুষ্ট হতে পারে যে একটি তালিকা এবং মাল্টিসেট (এমসেট) আরও দুটি আকর্ষণীয়, গাণিতিক ডেটা কাঠামো:

  • তালিকা : উপাদানগুলির একটি আদেশযুক্ত ধারক যা প্রতিলিপিগুলিকে অনুমতি দেয় (কার্যকর)
  • এমসেট : উপাদানগুলির একটি আনর্ডারড ধারক যা প্রতিলিপিগুলিকে অনুমতি দেয় (NotImplemented) *

সারসংক্ষেপ

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

* একটি বহুলিপি অপ্রত্যক্ষভাবে অনুকরণ করা যেতে পারে collections.Counter(), ডিকের মতো বহুসংখ্যার ম্যাপিং (গণনা)।


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

সোভেনের উত্তরে বিল্ডিংয়ের সময় আমি সংগ্রহগুলি ব্যবহার করে পেয়েছি r

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 এ নয়, যদিও আমার উল্লেখ করা উচিত ছিল।
jimh

0

উপরের সর্বোচ্চ স্কোর ধারণার একটি বাস্তবায়ন যা এটিকে আবার তালিকায় নিয়ে আসে:

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

পাইথন ৩.6 এবং পাইথন ২.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}

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.