a = [1, 2, 3, 1, 2, 3]
b = [3, 2, 1, 3, 2, 1]
a & b ควรได้รับการพิจารณาอย่างเท่าเทียมกันเพราะพวกเขามีองค์ประกอบเดียวกันทุกประการเท่านั้น
สิ่งที่เป็นรายการจริงของฉันจะประกอบด้วยวัตถุ (อินสแตนซ์ชั้นเรียนของฉัน) ไม่ใช่จำนวนเต็ม
len()
ก่อน
a = [1, 2, 3, 1, 2, 3]
b = [3, 2, 1, 3, 2, 1]
a & b ควรได้รับการพิจารณาอย่างเท่าเทียมกันเพราะพวกเขามีองค์ประกอบเดียวกันทุกประการเท่านั้น
สิ่งที่เป็นรายการจริงของฉันจะประกอบด้วยวัตถุ (อินสแตนซ์ชั้นเรียนของฉัน) ไม่ใช่จำนวนเต็ม
len()
ก่อน
คำตอบ:
O (n) : วิธีการนับ ()เป็นวิธีที่ดีที่สุด (ถ้าวัตถุของคุณแฮช):
def compare(s, t):
return Counter(s) == Counter(t)
O (n log n) : วิธีการเรียง ()เป็นวิธีที่ดีที่สุดถัดไป (หากวัตถุของคุณสามารถสั่งซื้อได้):
def compare(s, t):
return sorted(s) == sorted(t)
O (n * n) : หากวัตถุนั้นไม่มีแฮชหรือไม่เป็นระเบียบคุณสามารถใช้ความเท่าเทียมกันได้:
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
sorted()
Counter
ผู้สัมภาษณ์ยืนยันว่ามีวิธีการที่มีประสิทธิภาพมากขึ้นและชัดเจนว่าฉันเขียนจดหมายเปล่า หลังจากการทดสอบอย่างกว้างขวางใน python 3 กับtimeit
โมดูลการเรียงลำดับจะออกมาอย่างรวดเร็วในรายการจำนวนเต็ม ในรายการของรายการ 1k ช้าลงประมาณ 1.5% และในรายการสั้น ๆ 10 รายการช้ากว่า 7.5% คิด?
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
.. ฉันอยากรู้มากว่าเกิดอะไรขึ้นที่นี่
คุณสามารถจัดเรียงทั้งสอง:
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__
แต่อาจเป็นไปไม่ได้สำหรับคอลเลกชัน
sorted([0, 1j])
หากคุณรู้ว่ารายการต่าง ๆ นั้น hashable อยู่เสมอคุณสามารถใช้สิ่งCounter()
ที่เป็น O (n)
หากคุณรู้ว่ารายการนั้นสามารถเรียงลำดับได้ตลอดเวลาคุณสามารถใช้sorted()
สิ่งที่เป็น O (n log n)
ในกรณีทั่วไปคุณไม่สามารถพึ่งพาการเรียงลำดับหรือมีองค์ประกอบดังนั้นคุณต้องมีทางเลือกเช่นนี้ซึ่งน่าเสียดายที่ O (n ^ 2)
len(a)==len(b) and all(a.count(i)==b.count(i) for i in a)
วิธีที่ดีที่สุดในการทำเช่นนี้คือการเรียงลำดับรายการและเปรียบเทียบ (การใช้Counter
จะไม่ทำงานกับวัตถุที่ไม่สามารถแฮชได้) สิ่งนี้ตรงไปตรงมาสำหรับจำนวนเต็ม:
sorted(a) == sorted(b)
มันยากขึ้นเล็กน้อยเมื่อใช้กับวัตถุใด ๆ หากคุณสนใจเกี่ยวกับตัวตนของวัตถุเช่นว่าวัตถุเดียวกันอยู่ในทั้งสองรายการคุณสามารถใช้id()
ฟังก์ชั่นเป็นคีย์การเรียงลำดับ
sorted(a, key=id) == sorted(b, key==id)
(ใน Python 2.x คุณไม่จำเป็นต้องใช้key=
พารามิเตอร์จริงๆเพราะคุณสามารถเปรียบเทียบวัตถุใด ๆ กับวัตถุใด ๆ การจัดเรียงนั้นเป็นกฎเกณฑ์ แต่มีเสถียรภาพดังนั้นจึงทำงานได้ดีสำหรับจุดประสงค์นี้มันไม่สำคัญว่าวัตถุจะเรียงตามลำดับอย่างไร ในการเรียงลำดับจะเหมือนกันสำหรับทั้งสองรายการใน Python 3 แม้ว่าการเปรียบเทียบออบเจ็กต์ประเภทต่าง ๆ จะไม่ได้รับอนุญาตในหลาย ๆ สถานการณ์ - ตัวอย่างเช่นคุณไม่สามารถเปรียบเทียบสตริงกับจำนวนเต็ม - ดังนั้นหากคุณจะมีวัตถุ ประเภทต่างๆควรใช้ ID ของวัตถุอย่างชัดเจน)
หากคุณต้องการเปรียบเทียบวัตถุในรายการตามค่าในทางกลับกันอันดับแรกคุณต้องกำหนดความหมายของ "ค่า" สำหรับวัตถุ จากนั้นคุณจะต้องใช้วิธีในการระบุว่าเป็นคีย์ (และสำหรับ Python 3 เป็นประเภทที่สอดคล้องกัน) repr()
วิธีการหนึ่งที่มีศักยภาพที่จะทำงานให้มากวัตถุโดยพลการคือการจัดเรียงของพวกเขา แน่นอนว่านี่อาจเสียเวลามากและการสร้างrepr()
สายหน่วยความจำสำหรับรายการขนาดใหญ่และอื่น ๆ
sorted(a, key=repr) == sorted(b, key==repr)
หากวัตถุเป็นประเภทของคุณเองคุณสามารถกำหนด__lt__()
วัตถุเหล่านั้นเพื่อให้วัตถุรู้วิธีเปรียบเทียบตัวเองกับผู้อื่น จากนั้นคุณสามารถเรียงลำดับและไม่ต้องกังวลเกี่ยวกับkey=
พารามิเตอร์ แน่นอนคุณสามารถกำหนด__hash__()
และใช้Counter
ซึ่งจะเร็วขึ้น
https://docs.python.org/3.5/library/unittest.html#unittest.TestCase.assertCountEqual
assertCountEqual (แรกวินาที msg = ไม่มี)
ทดสอบลำดับแรกนั้นมีองค์ประกอบเดียวกันกับที่สองโดยไม่คำนึงถึงลำดับ เมื่อไม่มีข้อความแสดงข้อผิดพลาดที่แสดงความแตกต่างระหว่างลำดับจะถูกสร้างขึ้น
องค์ประกอบที่ซ้ำกันจะไม่ถูกละเว้นเมื่อเปรียบเทียบก่อนและสอง ตรวจสอบว่าแต่ละองค์ประกอบมีจำนวนเท่ากันในทั้งสองลำดับ เทียบเท่ากับ: assertEqual (ตัวนับ (รายการ (แรก)), ตัวนับ (รายการ (ที่สอง))) แต่ทำงานกับลำดับของวัตถุที่ไม่สามารถล้างได้เช่นกัน
ใหม่ในเวอร์ชัน 3.2
หรือใน 2.7: https://docs.python.org/2.7/library/unittest.html#unittest.TestCase.assertItemsEqual
หากรายการมีรายการที่ไม่แฮช (เช่นรายการวัตถุ) คุณอาจสามารถใช้ฟังก์ชันCounter Classและ id () ได้เช่น:
from collections import Counter
...
if Counter(map(id,a)) == Counter(map(id,b)):
print("Lists a and b contain the same objects")
ฉันหวังว่าโค้ดด้านล่างอาจใช้ได้ในกรณีของคุณ: -
if ((len(a) == len(b)) and
(all(i in a for i in b))):
print 'True'
else:
print 'False'
สิ่งนี้จะช่วยให้แน่ใจว่าองค์ประกอบทั้งหมดในทั้งรายการa
& b
เหมือนกันโดยไม่คำนึงว่าอยู่ในลำดับเดียวกันหรือไม่
เพื่อความเข้าใจที่ดีขึ้นโปรดอ้างอิงคำตอบของฉันในคำถามนี้
หากจะทำการเปรียบเทียบในบริบทการทดสอบให้ใช้assertCountEqual(a, b)
( py>=3.2
) และassertItemsEqual(a, b)
( 2.7<=py<3.2
)
ทำงานบนลำดับของวัตถุที่ unhashable ด้วย
ให้ a, b แสดงรายการ
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
ไม่จำเป็นต้องทำให้พวกเขา hashable หรือจัดเรียงพวกเขา
a
สนับสนุนpop
(ไม่แน่นอน) และindex
(เป็นลำดับ) เรย์มอนด์สันนิษฐานว่าไม่ใช่ในขณะที่ gnibbler ถือว่าเป็นลำดับ
การใช้unittest
โมดูลให้แนวทางที่สะอาดและเป็นมาตรฐานแก่คุณ
import unittest
test_object = unittest.TestCase()
test_object.assertCountEqual(a, b)