পাইথনে দুটি অর্ডারড লিস্ট (সেট নয়) কীভাবে দক্ষতার সাথে তুলনা করবেন?


141
a = [1, 2, 3, 1, 2, 3]
b = [3, 2, 1, 3, 2, 1]

একটি & খকে সমান বিবেচনা করা উচিত, কারণ তাদের ঠিক একই উপাদান রয়েছে, কেবলমাত্র বিভিন্ন ক্রমে।

জিনিসটি হ'ল, আমার আসল তালিকাগুলিতে (আমার শ্রেণীর উদাহরণগুলি) পূর্ণসংখ্যা নয়।


7
কীভাবে বস্তুর তুলনা করা হয়?
মার্সেলো ক্যান্টোস

2
আসল তালিকার প্রত্যাশিত আকারটি কী? তালিকাগুলি তুলনাযোগ্য আকারের বা খুব আলাদা হবে? আপনি কি বেশিরভাগ তালিকাগুলি মিলবে কিনা আশা করেন?
দিমিত্রি বি।

কেউ len()প্রথমে পরীক্ষা করতে পারে ।
গ্রেইবার্ড

উত্তর:


245

ও (এন) : কাউন্টার () পদ্ধতিটি সর্বোত্তম (যদি আপনার জিনিসগুলি হ্যাশযোগ্য হয়):

def compare(s, t):
    return Counter(s) == Counter(t)

ও (এন লগ এন) : বাছাই করা () পদ্ধতিটি পরবর্তীটি সেরা (যদি আপনার বস্তুগুলি অগ্রণী হয়):

def compare(s, t):
    return sorted(s) == sorted(t)

ও (এন * এন) : অবজেক্টগুলি যদি না হ্যাশেবল হয় না বা অগ্রণী হয় না তবে আপনি সমতা ব্যবহার করতে পারেন:

def compare(s, t):
    t = list(t)   # make a mutable copy
    try:
        for elem in s:
            t.remove(elem)
    except ValueError:
        return False
    return not t

1
ধন্যবাদ. আমি প্রতিটি বস্তুকে স্ট্রিংয়ে রূপান্তরিত করে তারপরে কাউন্টার () পদ্ধতিটি ব্যবহার করি।
jhndir

আরে @Raymond, আমি সম্প্রতি এই প্রশ্নের এক সাক্ষাৎকারে উপর সম্মুখীন হয়েছে এবং আমি ব্যবহৃত sorted(), বোঝা যাচ্ছে যে নেতারা সম্পর্কে বুদ্ধিমান না Counter। সাক্ষাত্কারকারী জোর দিয়েছিলেন যে আরও কার্যকর পদ্ধতি আছে এবং স্পষ্টতই আমি একটি ফাঁকা আঁকছি। timeitমডিউলটি দিয়ে অজগর 3 তে বিস্তৃত পরীক্ষার পরে ধারাবাহিকভাবে সাজানো পূর্ণসংখ্যার তালিকায় দ্রুত চলে আসে faster 1k আইটেমের তালিকায়, প্রায় 1.5% ধীর এবং সংক্ষিপ্ত তালিকায় 10 টি আইটেম, 7.5% ধীর। থটস?
arctelix

4
সংক্ষিপ্ত তালিকার জন্য, বিগ-ও বিশ্লেষণ সাধারণত অপ্রাসঙ্গিক কারণ সময়গুলি ধ্রুবক উপাদানগুলির দ্বারা প্রাধান্য পায়। দীর্ঘ তালিকাগুলির জন্য, আমি সন্দেহ করি যে আপনার বেঞ্চমার্কিংয়ে কিছু ভুল আছে। প্রতিটি 5 টি পুনরাবৃত্তি সহ 100 টির জন্য, আমি পেয়েছি: বাছাইয়ের জন্য 127 ইউজেক এবং কাউন্টারের জন্য 42 (প্রায় 3x দ্রুত)। 5 পুনরাবৃত্তি সহ 1000 ints এ, কাউন্টারটি 4x দ্রুত। python3.6 -m timeit -s 'from collections import Counter' -s 'from random import shuffle' -s 't=list(range(100)) * 5' -s 'shuffle(t)' -s 'u=t[:]' -s 'shuffle(u)' 'Counter(t)==Counter(u)'
রেমন্ড হেটেঞ্জার

@ রেমন্ড প্রকৃতপক্ষে আমরা বিভিন্ন ফলাফল পাচ্ছি। আমি আমার সেটআপটি একটি চ্যাট রুমে পোস্ট করলাম sorted vs counter.. এখানে কী চলছে সে সম্পর্কে আমি খুব আগ্রহী।
arctelix

4
না ধন্যবাদ. স্পুরিয়াস টাইমিং স্ক্রিপ্টগুলি ডিবাগ করার ক্ষেত্রে আমার খুব বেশি আগ্রহ নেই। এখানে প্রচুর চলছে (খাঁটি পাইথন বনাম সি কোড, টাইমসোর্টটি এলোমেলো উপাত্ত বনাম আধা অর্ডারযুক্ত ডেটা প্রয়োগ করা হচ্ছে, সংস্করণে বিভিন্ন প্রয়োগের বিশদ বিবরণ, কতগুলি সদৃশ ডেটাতে রয়েছে ইত্যাদি)
রেমন্ড হেটিঙ্গার

16

আপনি উভয় বাছাই করতে পারেন:

sorted(a) == sorted(b)

একটি গণনা সাজানোর কাজটি আরও কার্যকর হতে পারে (তবে এটির জন্য হ্যাশেবল হওয়া দরকার)।

>>> from collections import Counter
>>> a = [1, 2, 3, 1, 2, 3]
>>> b = [3, 2, 1, 3, 2, 1]
>>> print (Counter(a) == Counter(b))
True

কাউন্টারে হ্যাশিং ব্যবহার করা হয় তবে অবজেক্টগুলি প্রতি সেউয়ের তুলনায় অপসারণযোগ্য নয়। আপনাকে কেবল একটি বুদ্ধিমান প্রয়োগ __hash__করতে হবে, তবে এটি সংগ্রহের পক্ষে অসম্ভব।
জোচেন রিটজেল

2
বাছাই করা প্রতিটি কাজের জন্য কাজ করবে না, উদাহরণস্বরূপ জটিল সংখ্যাsorted([0, 1j])
জন লা রোয়

1
সাজানো () এছাড়াও তুলনা অপারেটরদের সাবসেট / সুপারসেট পরীক্ষার জন্য ওভাররাইড করা হয়েছে এমন সেটগুলির সাথে কাজ করে না।
রেমন্ড হেটেঞ্জার

12

আপনি যদি জানেন যে আইটেমগুলি সর্বদা হ্যাশযোগ্য হয় তবে আপনি Counter()যা ব্যবহার করতে পারেন এটি ও (এন)
আপনি যদি জানেন যে আইটেমগুলি সর্বদা বাছাইযোগ্য হয় তবে আপনি sorted()যা ব্যবহার করতে পারেন এটি হে (এন লগ এন)

সাধারণ ক্ষেত্রে আপনি বাছাই করতে সক্ষম হওয়ার উপর নির্ভর করতে পারবেন না, বা উপাদানগুলিও থাকতে পারেন, সুতরাং আপনার এরকম একটি ফ্যালব্যাকের প্রয়োজন, যা দুর্ভাগ্যক্রমে ও (এন ^ 2)

len(a)==len(b) and all(a.count(i)==b.count(i) for i in a)

5

এটি করার সর্বোত্তম উপায় হ'ল তালিকাগুলি বাছাই করা এবং তাদের তুলনা করা। (ব্যবহার করা Counterহ্যাশযোগ্য নয় এমন বস্তুর সাথে কাজ করবে না)) এটি পূর্ণসংখ্যার জন্য সোজা:

sorted(a) == sorted(b)

এটি স্বেচ্ছাসেবী বিষয়গুলির সাথে একটি সামান্য কৌশলযুক্ত হয়। যদি আপনি অবজেক্টের পরিচয় সম্পর্কে উদ্বিগ্ন হন, অর্থাত্, উভয় তালিকায় একই জিনিসগুলি রয়েছে কিনা , আপনি id()সারণি কী হিসাবে ফাংশনটি ব্যবহার করতে পারেন ।

sorted(a, key=id) == sorted(b, key==id)

(পাইথন ২.x-এ আপনার আসলে key=প্যারামিটারের দরকার নেই , কারণ আপনি যে কোনও বস্তুর সাথে যে কোনও বস্তুর তুলনা করতে পারেন The ক্রমটি নির্বিচারে তবে স্থিতিশীল, তাই এটি এই উদ্দেশ্যে কার্যকর হয়; বস্তুগুলি কী আদেশ তা বিচার্য নয়) ইন, কেবলমাত্র উভয় তালিকার জন্য ক্রম একই। পাইথন 3 এ যদিও বিভিন্ন ধরণের অবজেক্টের তুলনা করা অনেক পরিস্থিতিতে অনুমোদিত নয় - উদাহরণস্বরূপ, আপনি স্ট্রিজকে পূর্ণসংখ্যার সাথে তুলনা করতে পারবেন না - সুতরাং যদি আপনার কাছে বস্তু থাকে বিভিন্ন ধরণের, স্পষ্টভাবে অবজেক্টের আইডি ব্যবহার করা ভাল best)

আপনার দ্বারা তালিকায় বস্তু তুলনা করতে চান তাহলে মান, অপরপক্ষে, প্রথমে আপনার অবজেক্টের জন্য কি "VALUE" মানে সংজ্ঞায়িত করা প্রয়োজন। তারপরে আপনার কীটি (এবং পাইথন 3 এর জন্য, ধারাবাহিক প্রকার হিসাবে) সরবরাহ করার জন্য কিছু উপায়ের প্রয়োজন হবে। একটি প্রচলিত উপায় যা প্রচুর স্বেচ্ছাচারিত বস্তুর জন্য কাজ করে তা হ'ল তাদের অনুসারে বাছাই করা repr()। অবশ্যই, এটি repr()বৃহত তালিকার জন্য আরও অনেক বেশি সময় এবং মেমরির বিল্ডিংয়ের স্ট্রিংগুলি নষ্ট করতে পারে ।

sorted(a, key=repr) == sorted(b, key==repr)

যদি বস্তুগুলি আপনার নিজস্ব সমস্ত ধরণের হয় তবে আপনি সেগুলির __lt__()উপরে সংজ্ঞা দিতে পারেন যাতে অবজেক্টটি কীভাবে নিজেকে অন্যের সাথে তুলনা করতে পারে তা জানে। তারপরে আপনি কেবল সেগুলি বাছাই করতে পারেন এবং key=প্যারামিটার সম্পর্কে চিন্তা করবেন না । অবশ্যই আপনি সংজ্ঞা __hash__()এবং ব্যবহার করতে পারেন Counter, যা দ্রুত হবে।


4

https://docs.python.org/3.5/library/unittest.html#unittest.TestCase.assertCountEqual

assertCountEqual (প্রথম, দ্বিতীয়, চিহ্ন = কিছুই নয়)

সেই ক্রমটি পরীক্ষা করুন যাতে প্রথমে তাদের অর্ডার নির্বিশেষে দ্বিতীয় হিসাবে একই উপাদান থাকে। যখন তারা না করে, ক্রমগুলির মধ্যে পার্থক্যগুলি তালিকাভুক্ত করার একটি ত্রুটি বার্তা উত্পন্ন হবে।

প্রথম এবং দ্বিতীয়টির তুলনা করার সময় সদৃশ উপাদানগুলি এড়ানো হবে না। উভয় অনুক্রমের প্রতিটি উপাদানের একই গণনা রয়েছে কিনা তা যাচাই করে। এর সমতুল্য: assertEqual (কাউন্টার (তালিকা (প্রথম)), কাউন্টার (তালিকা (দ্বিতীয়))) তবে অখাদ্য বস্তুর ক্রমগুলির সাথেও কাজ করে।

সংস্করণে নতুন 3.2।

বা ২.7 এ: https://docs.python.org/2.7/library/unittest.html#unittest.TestCase.assertItemsEqual


2
(কি এই জোড়ে jarekwg এর উত্তর ?)
বৃদ্ধলোক

3

তালিকায় যদি এমন আইটেম থাকে যেগুলি হ্যাশযোগ্য নয় (যেমন সামগ্রীর তালিকাগুলি) আপনি কাউন্টার ক্লাস এবং আইডি () ফাংশন যেমন:

from collections import Counter
...
if Counter(map(id,a)) == Counter(map(id,b)):
    print("Lists a and b contain the same objects")

2

আমি আশা করি নীচের কোডের টুকরোটি আপনার ক্ষেত্রে কাজ করতে পারে: -

if ((len(a) == len(b)) and
   (all(i in a for i in b))):
    print 'True'
else:
    print 'False'

এই উভয় তালিকায় সব উপাদান নিশ্চিত করবে abএকই রকম, কিনা তারা একই আদেশ বা না নির্বিশেষে।

আরও ভাল বোঝার জন্য, এই প্রশ্নের আমার উত্তর দেখুন


2

যদি তুলনাটি পরীক্ষার প্রসঙ্গে করা হয়, assertCountEqual(a, b)( py>=3.2) এবং assertItemsEqual(a, b)( 2.7<=py<3.2) ব্যবহার করুন।

অদৃশ্যযোগ্য বস্তুর ক্রমগুলিতেও কাজ করে।


1

একটি, খ তালিকা দেওয়া যাক

def ass_equal(a,b):
try:
    map(lambda x: a.pop(a.index(x)), b) # try to remove all the elements of b from a, on fail, throw exception
    if len(a) == 0: # if a is empty, means that b has removed them all
        return True 
except:
    return False # b failed to remove some items from a

এগুলিকে হ্যাশযোগ্য বা বাছাই করার দরকার নেই।


1
হ্যাঁ তবে এটি ও (এন ** 2) হিসাবে অন্যান্য বেশ কয়েকটি পোস্টারের বক্তব্য অনুসারে, অন্য পদ্ধতিগুলি যদি কাজ না করে তবেই এটি ব্যবহার করা উচিত। এছাড়া অনুমান aসমর্থন pop(চপল হয়) এবং index(ক ক্রম)। জিমিবলারের কেবল একটি অনুক্রম হিসাবে রাইমন্ডের ধারণা অনুমান করা হয় না।
agf

0

unittestমডিউলটি ব্যবহার করা আপনাকে একটি পরিষ্কার এবং মানক পদ্ধতির দেয়।

import unittest

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