পাইথন তালিকা বিয়োগ অপারেশন


227

আমি এর অনুরূপ কিছু করতে চাই:

>>> x = [1,2,3,4,5,6,7,8,9,0]  
>>> x  
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]  
>>> y = [1,3,5,7,9]  
>>> y  
[1, 3, 5, 7, 9]  
>>> y - x   # (should return [2,4,6,8,0])

তবে এটি অজগর তালিকার দ্বারা সমর্থিত নয় এটি করার সর্বোত্তম উপায়টি কী?


@ezdazuzena এটি বিয়োগ নয়। এটি দুটি তালিকার মধ্যে পার্থক্য। আপনার ভাগ করে নেওয়া এই প্রশ্নের একটি প্রজাতন্ত্র নয়।
সেলিক

1
[2, 2] - [2] কী ফিরে আসবে? []? [2]?
ম্যাককে

@ এমসিকে [২,২] - [২] [২] ফেরত আসবে। [2,2] - [1,2,2,3] ফিরতে হবে []
রবিনো

এই প্রশ্নটি তালিকা বিয়োগ সম্পর্কে তবে স্বীকৃত উত্তর বিয়োগফলের কাছাকাছি।
রবিনো

2
[2, 1, 2, 3, 2, 4, 2] - [2, 3, 2] কী ফিরে আসবে এবং কেন? এটি মাঝখানে 232 খুঁজে পাওয়া এবং 2142 ফিরে পাওয়া উচিত? অথবা এটি প্রতিটি বার প্রথম খুঁজে পাওয়া এবং 1242 ফেরত পাওয়া উচিত? অথবা অন্য কিছু? আমি যা বলছি তা হ'ল এগুলি সুস্পষ্ট উত্তর নয় এবং প্রয়োজনের উপর নির্ভর করে।
ম্যাককে

উত্তর:


330

একটি তালিকা বোধগম্যতা ব্যবহার করুন:

[item for item in x if item not in y]

আপনি যদি -ইনফিক্স বাক্য গঠন ব্যবহার করতে চান তবে আপনি কেবল এটি করতে পারেন:

class MyList(list):
    def __init__(self, *args):
        super(MyList, self).__init__(args)

    def __sub__(self, other):
        return self.__class__(*[item for item in self if item not in other])

তারপরে আপনি এটির মতো ব্যবহার করতে পারেন:

x = MyList(1, 2, 3, 4)
y = MyList(2, 5, 2)
z = x - y   

তবে যদি আপনার অবশ্যই তালিকার বৈশিষ্ট্যগুলির প্রয়োজন না হয় (উদাহরণস্বরূপ, ক্রম), অন্য উত্তরগুলির পরামর্শ অনুসারে কেবল সেটগুলি ব্যবহার করুন।


10
@ অ্যাডমিকা, listপরিবর্তনশীল নামের জন্য এটি ব্যবহারকারীর ছায়া হিসাবে ব্যবহার করবেন না list। আপনি যদি 'তালিকা' ব্যবহার করেন তবে দয়া করে এটি একটি আন্ডারস্কোর দিয়ে আগে রেখে দিন। এছাড়াও, বাদ দিয়ে *আপনি আমার কোডটি ভেঙে দিয়েছিলেন ...
অ্যারোনস্টার্লিং

19
আপনি যদি [1,1,2,2] - [1,2]খালি তালিকা পাবেন। [1,1,2,2] - [2]দেয় [1,1]সুতরাং এটি সত্যিই তালিকা বিয়োগ নয়, এটা আরও ভালো হয় "তালিকা থেকে তালিকা এক্স সেট থেকে উপাদানগুলি ছাড়া ওয়াই "
আলফ্রেড জিয়েন

@ অ্যালফ্রেডজিয়েন তিনি যা বলেছিলেন
রেট্রোড

তালিকাটি বোঝার পদ্ধতিটি সেট পার্থক্য পদ্ধতির চেয়ে ধীরে ধীরে (আমার উদাহরণে)।
redfiloux

1
@BarnabasSzabolcs: যে একটা জিনিস না সংরক্ষণ করতে হবে কারণ এটি রূপান্তর করবে yএকটি থেকে setসামনে যে চেক (যা মূল কাজের অনুরূপ খরচ)। আপনি হয় yset = set(y)লিস্টকম্পের বাইরে পরীক্ষা করতে হবে, তারপরে পরীক্ষা করতে if item not in ysetবা একটি গুরুতর হ্যাক হিসাবে, [item for yset in [set(y)] for item in x if item not in yset]যা ওয়ানডাইনার ysetহিসাবে ক্যাশে রাখতে নেস্টেড লিস্টকম্পগুলিকে আপত্তি জানায় । কিছুটা কম কুরুচিপূর্ণ ওয়ান-লাইনারের সমাধান যা পর্যাপ্ত পরিমাণে পারফর্ম করে তা ব্যবহার করা হবে list(itertools.filterfalse(set(y).__contains__, x))কারণ তর্কটি filterfalseকেবল একবার তৈরি হয়েছিল।
শ্যাডোর্যাঞ্জার

259

সেট পার্থক্য ব্যবহার করুন

>>> z = list(set(x) - set(y))
>>> z
[0, 8, 2, 4, 6]

অথবা আপনার এক্স এবং ওয়াই সেট থাকতে পারে যাতে আপনার কোনও রূপান্তর করতে হবে না।


50
এটি কোনও ক্রম হারাবে। প্রসঙ্গের উপর নির্ভর করে এটি বা নাও পারে।
অ্যারোনস্টার্লিং

63
এটি রক্ষণাবেক্ষণের প্রয়োজন হতে পারে এমন যে কোনও সম্ভাব্য নকলও looseিলা করবে।
ওপল

আমি পেয়েছিTypeError: unhashable type: 'dict'
হাভনার

তালিকার তুলনায় তুলনামূলক বড় আকারের ক্ষেত্রে এটি খুব দ্রুত
JqueryToAddNumbers

2
যদি তালিকার আইটেমগুলির অর্ডার এবং ডুপ্লিকেটগুলি প্রসঙ্গে গুরুত্বপূর্ণ না হয় তবে এটি একটি দুর্দান্ত উত্তর এবং এটি খুব পঠনযোগ্য।
ওয়াট ইয়ামসুরি 25'19

37

এটি একটি "সেট বিয়োগ" অপারেশন। তার জন্য সেট ডেটা কাঠামোটি ব্যবহার করুন।

পাইথন ২.7 এ:

x = {1,2,3,4,5,6,7,8,9,0}
y = {1,3,5,7,9}
print x - y

আউটপুট:

>>> print x - y
set([0, 8, 2, 4, 6])

1
তালিকা (সেট ([1,2,3,4,5]) - সেট ([1,2,3])) = [4, 5] যাতে প্রথমে প্রতিটি সেট করে তালিকা তৈরি করা হয়, তারপরে বিয়োগ (বা একমুখী পার্থক্য) ) এবং তালিকায় ফিরে যান।
গিসিটল

2
আপনি যদি x সেটের মূল আইটেম অর্ডার বজায় রাখতে চান তবে ভাল নয়।
জহরান

34

যদি নকল এবং ক্রম আইটেম সমস্যা হয়:

[i for i in a if not i in b or b.remove(i)]

a = [1,2,3,3,3,3,4]
b = [1,3]
result: [2, 3, 3, 3, 4]

2
এটি কাজ করে, যদিও এটি O(m * n)রানটাইম (এবং আমি যখনই কোনও লিস্টকম্পে পার্শ্ব-প্রতিক্রিয়াগুলিকে অন্তর্ভুক্ত করি তখনই আমি ক্রিঞ্জ করি); রানটাইম পাওয়ার জন্য আপনি এতে উন্নতি করতে পারেনcollections.CounterO(m + n)
শ্যাডোর্যাঞ্জার

এটি বুঝতে আমার খুব কষ্ট হচ্ছে, কেউ কি ব্যাখ্যা করতে পারেন?
আনুশকা

20

অনেকগুলি ব্যবহারের ক্ষেত্রে, আপনি যে উত্তরটি চান তা হ'ল:

ys = set(y)
[item for item in x if item not in ys]

এটি অ্যারোনস্টার্লিংয়ের উত্তর এবং কোয়ান্টামসুপের উত্তরগুলির মধ্যে একটি সংকর ।

অ্যারোনস্টার্লিংয়ের সংস্করণ len(y)প্রতিটি উপাদানের সাথে আইটেমের তুলনা করে x, তাই এটি চতুর্ভুজ সময় নেয়। quantumSoup এর সংস্করণ ব্যবহার সেট, তাই এটি প্রতিটি উপাদান জন্য একটি একক ধ্রুবক-টাইম সেট লুকআপ না x-কিন্তু, কারণ এটি পরিবর্তন করে উভয় x এবং yসেটে, এটা আপনার উপাদানের ক্রম হারায়।

কেবলমাত্র yএকটি সেটে রূপান্তর করে xএবং ক্রমে পুনরাবৃত্তি করার মাধ্যমে আপনি উভয় বিশ্বের সেরা — রৈখিক সময় এবং অর্ডার সংরক্ষণ পান *


তবে এটি এখনও কোয়ান্টামসুপের সংস্করণ থেকে একটি সমস্যা রয়েছে: এটির জন্য আপনার উপাদানগুলি হ্যাশযোগ্য হওয়া দরকার। এটি সেটগুলির প্রকৃতিতে নির্মিত হয়েছে *

আপনি যদি নিজের মানগুলি কোনওভাবে সাজাতে পারেন তবে এটি সমস্যার সমাধান করে dec উদাহরণস্বরূপ, একটি সমতল অভিধানের সাথে যার মানগুলি নিজেরাই হাশেবল:

ys = {tuple(item.items()) for item in y}
[item for item in x if tuple(item.items()) not in ys]

যদি আপনার প্রকারগুলি কিছুটা আরও জটিল হয় (উদাহরণস্বরূপ, আপনি প্রায়শই JSON- সামঞ্জস্যপূর্ণ মানগুলির সাথে লেনদেন করেন যা হ্যাশযোগ্য, বা তালিকা বা dicts যার মানগুলি পুনরাবৃত্তভাবে একই ধরণের হয়) তবে আপনি এখনও এই সমাধানটি ব্যবহার করতে পারেন। তবে কিছু প্রকার কেবল হ্যাশযোগ্য কিছুতে রূপান্তর করা যায় না।


যদি আপনার আইটেমগুলি না তৈরি হয় এবং এটি তৈরি করা যায় না, তড়িঘড়ি করতে সক্ষম হয় তবে সেগুলি তুলনামূলক হয় তবে আপনি কমপক্ষে লগ-লিনিয়ার সময় পেতে পারেন ( O(N*log M)যা O(N*M)তালিকার সমাধানের সময়ের চেয়ে অনেক ভাল , তবে যতটা ভাল না O(N+M)সেট সমাধানের সময়) বাছাই এবং ব্যবহার করে bisect:

ys = sorted(y)
def bisect_contains(seq, item):
    index = bisect.bisect(seq, item)
    return index < len(seq) and seq[index] == item
[item for item in x if bisect_contains(ys, item)]

যদি আপনার আইটেমগুলি নাও ধাবনযোগ্য বা তুলনীয় হয় না, তবে আপনি চতুর্ভুজ সমাধানের সাথে আটকে আছেন।


* নোট করুন যে আপনি একজোড়া OrderedSetঅবজেক্ট ব্যবহার করে এটিও করতে পারেন, যার জন্য আপনি রেসিপি এবং তৃতীয় পক্ষের মডিউলগুলি খুঁজে পেতে পারেন। তবে আমি মনে করি এটি সহজ।

** কারণ নির্ধারণের জন্য ধ্রুবক সময় হ'ল এটির যা করতে হবে তা হ্যাশ হ'ল এবং দেখুন যে হ্যাশের জন্য কোনও প্রবেশ আছে কিনা। যদি এটি মানটি হ্যাশ করতে না পারে তবে এটি কাজ করবে না।


7

সেটে মানগুলি সন্ধান করা তালিকায় তাদের সন্ধানের চেয়ে দ্রুত হয়:

[item for item in x if item not in set(y)]

আমি বিশ্বাস করি এটির থেকে কিছুটা ভাল স্কেল হবে:

[item for item in x if item not in y]

উভয়ই তালিকার ক্রম সংরক্ষণ করে।


এটি কি ক্যাশে হবে set(y)এবং yপ্রতিটি লুপে নতুন সেটে রূপান্তরিত হবে না ? অন্যথা, আপনি প্রয়োজন abarnert এর উত্তর চাই: ys = set(y); [i for i in x if i not in ys]
জ্যাকটোজ

2
কিছু মোটামুটি পরীক্ষার পরামর্শ দেয় যে (যেখানে তালিকা রয়েছে) এর if i not in set(y)চেয়ে 25% বেশি সময় নেয় । সেটটিকে প্রাক রূপান্তর করতে 55% কম সময় লাগে। বেশ সংক্ষিপ্ত এবং পরীক্ষা করা হয়েছে , তবে পার্থক্যগুলি দৈর্ঘ্যের সাথে আরও স্পষ্ট হওয়া উচিত, যদি কিছু থাকে। if i not in yyxy
জ্যাকটোজ

1
@Jacktose: হ্যাঁ, এই সমাধান করা হয়েছে কারণ এটি বারবার করা এবং হ্যাশ রয়েছে, আরো কাজ করে যে উপাদান yজন্য যে উপাদান x; সাম্য তুলনা হ্যাশ গণনার তুলনায় সত্যই ব্যয়বহুল না হলে এটি সর্বদা প্লেইনে হারাবে item not in y
শ্যাডোর্যাঞ্জার

পছন্দ করুন যদি সেট রূপান্তরটি সেই চেকটি করার জন্য নির্ভরযোগ্যভাবে দ্রুততর উপায় হয় তবে আপনি ভাবেন যে সংকলকটি সর্বদা সেইভাবে চেকটি করবেন।
জ্যাকটোজ

5

যদি তালিকাগুলি সদৃশ উপাদানগুলিকে মঞ্জুরি দেয় তবে আপনি সংগ্রহগুলি থেকে কাউন্টার ব্যবহার করতে পারেন:

from collections import Counter
result = list((Counter(x)-Counter(y)).elements())

যদি আপনাকে x থেকে উপাদানগুলির ক্রম সংরক্ষণ করতে হয়:

result = [ v for c in [Counter(y)] for v in x if not c[v] or c.subtract([v]) ]

এটি ভাল, যদিও এটি ক্রম হারায় না; ফিক্সিং যা কিছুটা জটিল
শ্যাডোর্যাঞ্জার

@ শ্যাডোএ্যাঞ্জার, এটি সত্যই। তবে কিছুটা
আলাইন টি।

আমার কিছু মনে করবেন না, আমি কেবল ক্যাচিং এবং পার্শ্ব-প্রতিক্রিয়া সহ লিস্টকম্পগুলিতে কাঁপতে যাচ্ছি (যদিও আমি মনে করি উভয়ের সংমিশ্রণটি বাহ্যিকভাবে দৃশ্যমান পার্শ্ব-প্রতিক্রিয়াগুলি সরিয়ে দেয়?)। :-)
শ্যাডোর্যাঞ্জার

এছাড়াও, এই কোডটি লিখিত হিসাবে কাজ করবে না; Counter.subtractশূন্য মূল্যবান উপাদানগুলি সরান না ( -এবং -=করুন, তবে না subtract), সুতরাং আপনি কখনই উপাদানগুলি অপসারণ বন্ধ করবেন না। আপনি এর not v in cসাথে প্রতিস্থাপন করতে চান not c[v](যা অস্তিত্বের উপাদানগুলির জন্য শূন্য ফেরত দেয়, তাই আপনি "শূন্যতা" এর মাধ্যমে রিটার্নটি নিরাপদে পরীক্ষা করতে পারেন not)।
শ্যাডোর্যাঞ্জার

@ শ্যাডোএ্যাঞ্জার, ভাল ক্যাচ! এটি এখনই স্থির করুন।
আলাইন টি।

3

অন্যান্য সমাধানগুলির কয়েকটি সমস্যাগুলির মধ্যে একটি রয়েছে:

  1. তারা অর্ডার সংরক্ষণ করে না, বা
  2. তারা উপাদানগুলির একটি নির্দিষ্ট গণনা অপসারণ করে না, উদাহরণস্বরূপ x = [1, 2, 2, 2]এবং y = [2, 2]তারা একটিতে রূপান্তরিত yকরে setএবং হয় সমস্ত মিলিত উপাদানগুলি সরিয়ে দেয় ( [1]কেবল রেখে যায় ) বা প্রতিটি অনন্য উপাদানকে (অপসারণ) অপসারণ করে [1, 2, 2], যখন যথাযথ আচরণ 2দু'বার অপসারণ করা হবে, ছেড়ে [1, 2], বা
  3. তারা O(m * n)কাজ করে, যেখানে একটি অনুকূল সমাধান O(m + n)কাজ করতে পারে

অ্যালাইনCounter # 2 এবং # 3 সমাধান করার জন্য সঠিক পথে ছিলেন , তবে সেই সমাধান ক্রম হারাবে। অর্ডার সংরক্ষণ করা সমাধান (মুছে ফেলার মানগুলির পুনরাবৃত্তির nজন্য প্রতিটি মানের প্রথম কপিগুলি অপসারণ):nlist

from collections import Counter

x = [1,2,3,4,3,2,1]  
y = [1,2,2]  
remaining = Counter(y)

out = []
for val in x:
    if remaining[val]:
        remaining[val] -= 1
    else:
        out.append(val)
# out is now [3, 4, 3, 1], having removed the first 1 and both 2s.

এটি অনলাইন চেষ্টা করুন!

এটি অপসারণ করতে গত প্রতিটি উপাদান কপি শুধু পরিবর্তন forকরতে লুপ for val in reversed(x):যোগ out.reverse()থেকে প্রস্থান পরে অবিলম্বে forলুপ।

নির্মাণের Counterহয় O(n)পরিপ্রেক্ষিতে yএর দৈর্ঘ্য, iterating xহয় O(n)পরিপ্রেক্ষিতে xগুলি দৈর্ঘ্য ', এবং Counterসদস্য টেস্টিং এবং পরিব্যক্তি হয় O(1), যখন list.appendamortized হয় O(1)(একটি প্রদত্ত appendহতে পারে O(n)অনেকের জন্য, কিন্তু appendগুলি সামগ্রিক বড় হে গড় O(1)যেহেতু কম এবং কম তাদের মধ্যে একটি পুনঃনির্ধারণের প্রয়োজন হয়), তাই সামগ্রিকভাবে কাজটি হয়ে যায় O(m + n)

আপনি পরীক্ষা করে পরীক্ষা করতে পারেন যে এমন কোনও উপাদান রয়েছে yযা xপরীক্ষার মাধ্যমে অপসারণ করা হয়নি :

remaining = +remaining  # Removes all keys with zero counts from Counter
if remaining:
    # remaining contained elements with non-zero counts

দ্রষ্টব্য: এই না hashable হতে মানের দরকার হয়, কিন্তু কোনো সমাধান hashable বস্তু প্রয়োজন হয় না পারেন সাধারণ কাজের নয় (যেমন নির্ভর করতে পারেন intনির্দিষ্ট দৈর্ঘ্য অ্যারের মধ্যে গুলি) বা চেয়ে বেশি কি আছে O(m + n)কাজ (যেমন পরবর্তী সেরা বড় -আমাকে সাজানো listএক অনন্য মূল্য / গণনা O(1) dictজুড়ি তৈরি করা হবে, O(log n)বাইনারি অনুসন্ধানগুলিতে চেহারা পরিবর্তন করা ; আপনার অনন্য বৈশিষ্ট্যগুলি কেবল অনন্য-অনন্য মান অনুসারে বাছাই করা নয়, কারণ আপনার O(n)প্রয়োজনের অপসারণের জন্য ব্যয় করতে হবে বাছাই করা থেকে উপাদান list)।
শ্যাডোর্যাঞ্জার

2

এটা চেষ্টা কর.

def subtract_lists(a, b):
    """ Subtracts two lists. Throws ValueError if b contains items not in a """
    # Terminate if b is empty, otherwise remove b[0] from a and recurse
    return a if len(b) == 0 else [a[:i] + subtract_lists(a[i+1:], b[1:]) 
                                  for i in [a.index(b[0])]][0]

>>> x = [1,2,3,4,5,6,7,8,9,0]
>>> y = [1,3,5,7,9]
>>> subtract_lists(x,y)
[2, 4, 6, 8, 0]
>>> x = [1,2,3,4,5,6,7,8,9,0,9]
>>> subtract_lists(x,y)
[2, 4, 6, 8, 0, 9]     #9 is only deleted once
>>>

2

আমি মনে করি এটি অর্জনের সবচেয়ে সহজ উপায় হ'ল সেট () ব্যবহার করে।

>>> x = [1,2,3,4,5,6,7,8,9,0]  
>>> y = [1,3,5,7,9]  
>>> list(set(x)- set(y))
[0, 2, 4, 6, 8]

1

@ অ্যারোনাস্টারলিংয়ের সরবরাহ করা উত্তরটি দেখতে ভাল দেখাচ্ছে, তবে এটি তালিকার ডিফল্ট ইন্টারফেসের সাথে উপযুক্ত নয়: x = MyList(1, 2, 3, 4)বনাম x = MyList([1, 2, 3, 4])। সুতরাং, নীচের কোডটি আরও অজগর-তালিকা বান্ধব হিসাবে ব্যবহার করা যেতে পারে:

class MyList(list):
    def __init__(self, *args):
        super(MyList, self).__init__(*args)

    def __sub__(self, other):
        return self.__class__([item for item in self if item not in other])

উদাহরণ:

x = MyList([1, 2, 3, 4])
y = MyList([2, 5, 2])
z = x - y

0

আমি মনে করি এটি দ্রুততর:

In [1]: a = [1,2,3,4,5]

In [2]: b = [2,3,4,5]

In [3]: c = set(a) ^ set(b)

In [4]: c
Out[4]: {1}

এটি বিয়োগ নয়। আসলে, এটি দুটি তালিকার মধ্যে প্রতিসম পার্থক্য difference
পার্থ চৌহান

তবু এটি তালিকার অভ্যন্তরে কেবলমাত্র হাস্যযোগ্য বস্তুর জন্য কাজ করে
zhukovgreen

-1

এই উদাহরণ দুটি তালিকা বিয়োগ করে:

# List of pairs of points
list = []
list.append([(602, 336), (624, 365)])
list.append([(635, 336), (654, 365)])
list.append([(642, 342), (648, 358)])
list.append([(644, 344), (646, 356)])
list.append([(653, 337), (671, 365)])
list.append([(728, 13), (739, 32)])
list.append([(756, 59), (767, 79)])

itens_to_remove = []
itens_to_remove.append([(642, 342), (648, 358)])
itens_to_remove.append([(644, 344), (646, 356)])

print("Initial List Size: ", len(list))

for a in itens_to_remove:
    for b in list:
        if a == b :
            list.remove(b)

print("Final List Size: ", len(list))

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