[英]How to efficiently compare two sets of unordered vectors (`np.ndarray`)?
[英]How to efficiently compare two unordered lists (not sets)?
a = [1, 2, 3, 1, 2, 3]
b = [3, 2, 1, 3, 2, 1]
a & b 應該被認為是相等的,因為它們具有完全相同的元素,只是順序不同。
問題是,我的實際列表將包含對象(我的 class 實例),而不是整數。
O(n) : Counter()方法是最好的(如果您的對象是可散列的):
def compare(s, t):
return Counter(s) == Counter(t)
O(n log n) : sorted()方法是次佳的(如果您的對象是可訂購的):
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(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
如果您知道這些項目始終是可散列的,則可以使用 O(n) 的Counter()
)
如果您知道這些項目始終是可排序的,則可以使用sorted()
,即 O(n log n)
在一般情況下,您不能依賴能夠排序或擁有元素,因此您需要像這樣的后備,不幸的是 O(n^2)
len(a)==len(b) and all(a.count(i)==b.count(i) for i in a)
如果您必須在測試中執行此操作: https ://docs.python.org/3.5/library/unittest.html#unittest.TestCase.assertCountEqual
assertCountEqual(first, second, msg=None)
測試該序列首先包含與第二個相同的元素,無論它們的順序如何。 如果不這樣做,將生成列出序列之間差異的錯誤消息。
比較第一個和第二個時不會忽略重復的元素。 它驗證每個元素在兩個序列中是否具有相同的計數。 等價於:assertEqual(Counter(list(first)), Counter(list(second))) 但也適用於不可散列對象的序列。
3.2 版中的新功能。
或在 2.7 中: https ://docs.python.org/2.7/library/unittest.html#unittest.TestCase.assertItemsEqual
在測試之外,我會推薦Counter
方法。
如果要在測試上下文中執行比較,請使用assertCountEqual(a, b)
( py>=3.2
) 和assertItemsEqual(a, b)
( 2.7<=py<3.2
)。
也適用於不可散列對象的序列。
最好的方法是對列表進行排序並進行比較。 (使用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
,這樣會更快。
如果列表包含不可散列的項目(例如對象列表),您可能可以使用Counter 類和 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
中的所有元素都相同,無論它們的順序是否相同。
為了更好地理解,請參閱我在這個問題中的回答
讓 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
無需使它們可散列或對它們進行排序。
您可以編寫自己的函數來比較列表。
讓我們得到兩個列表。
list_1=['John', 'Doe']
list_2=['Doe','Joe']
首先,我們定義一個空字典,統計列表項並寫入字典。
def count_list(list_items):
empty_dict={}
for list_item in list_items:
list_item=list_item.strip()
if list_item not in empty_dict:
empty_dict[list_item]=1
else:
empty_dict[list_item]+=1
return empty_dict
之后,我們將使用以下函數比較兩個列表。
def compare_list(list_1, list_2):
if count_list(list_1)==count_list(list_2):
return True
return False
compare_list(list_1,list_2)
from collections import defaultdict
def _list_eq(a: list, b: list) -> bool:
if len(a) != len(b):
return False
b_set = set(b)
a_map = defaultdict(lambda: 0)
b_map = defaultdict(lambda: 0)
for item1, item2 in zip(a, b):
if item1 not in b_set:
return False
a_map[item1] += 1
b_map[item2] += 1
return a_map == b_map
如果數據高度無序,排序可能會非常慢(當項目具有某種程度的排序時,timsort 會特別好)。 對兩者進行排序還需要對兩個列表進行完全迭代。
與其改變一個列表,不如分配一個集合並進行左-->右成員資格檢查,同時記錄沿途存在的每個項目的數量:
False
。a
中不在列表b
中的任何項目,您可以返回False
a_map
和b_map
的值以找出它們是否匹配。這允許您在迭代兩個列表之前很久就在許多情況下短路。
插入這個:
def lists_equal(l1: list, l2: list) -> bool:
"""
import collections
compare = lambda x, y: collections.Counter(x) == collections.Counter(y)
ref:
- https://stackoverflow.com/questions/9623114/check-if-two-unordered-lists-are-equal
- https://stackoverflow.com/questions/7828867/how-to-efficiently-compare-two-unordered-lists-not-sets
"""
compare = lambda x, y: collections.Counter(x) == collections.Counter(y)
set_comp = set(l1) == set(l2) # removes duplicates, so returns true when not sometimes :(
multiset_comp = compare(l1, l2) # approximates multiset
return set_comp and multiset_comp #set_comp is gere in case the compare function doesn't work
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.