programing

순서가 매겨지지 않은 2개의 리스트(세트 이외)를 효율적으로 비교하려면 어떻게 해야 합니까?

goodsources 2022. 9. 8. 22:51
반응형

순서가 매겨지지 않은 2개의 리스트(세트 이외)를 효율적으로 비교하려면 어떻게 해야 합니까?

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

a와 b는 완전히 동일한 요소를 가지며 순서가 다르기 때문에 동등하다고 간주해야 합니다.

실제 리스트는 정수가 아닌 오브젝트(클래스 인스턴스)로 구성됩니다.

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): 객체가 해시 가능하지도 않고 오더 가능하지도 않은 경우 equality를 사용할 수 있습니다.

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

이 항상 " " " 를할 수 있습니다.Counter() o O(n) 다 다 다 다 which which which which which which which which
을 항상 수 것을 있는 , 을할 수 .sorted()Olog n)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★★★★★★ 。

가장 좋은 하는 것입니다.Counter해시할 수 없는 오브젝트에서는 동작하지 않습니다.)이것은 정수의 경우 간단합니다.

sorted(a) == sorted(b)

임의의 오브젝트에서는 조금 더 까다로워집니다.오브젝트 ID(, 양쪽 목록에 동일한 오브젝트가 있는지 여부)에 관심이 있는 경우id()정렬 키로 기능합니다.

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

2.x에서는 (Python 2.x, Python 2.x, Python, Python.x, Python.x 에서는 실제로 필요하지 key=임의의 오브젝트를 임의의 오브젝트와 비교할 수 있기 때문입니다.순서는 임의이지만 안정적이기 때문에 이 목적에서는 정상적으로 동작합니다.오브젝트의 순서는 중요하지 않습니다.단, 순서는 양쪽 리스트에서 동일합니다. Python에서는 여러 상황에서 하는 것은 허용되지 를 들어 정수와 수 없기 오브젝트가 있는 하는 것이 좋습니다.) Python 3은 이 오브젝트의 ID를 명시적으로 사용하는 것이 좋습니다. 예를 들어 문자열을 정수와 비교할 수 없으므로 다양한 유형의 개체가 있을 경우 개체의 ID를 명시적으로 사용하는 것이 좋습니다.)

한편, 리스트의 오브젝트를 값별로 비교하려면 먼저 오브젝트에 대해 "value"가 무엇을 의미하는지 정의해야 합니다.그러면 그것을 키로 제공할 수 있는 방법이 필요합니다(그리고 Python 3의 경우 일관된 유형으로).많은 임의의 오브젝트에 대해 동작할 수 있는 잠재적인 방법 중 하나는 자신의 오브젝트별로 정렬하는 것입니다.repr()물론, 이것은 많은 시간과 메모리를 낭비할 수 있습니다.repr()큰 리스트의 문자열 등입니다.

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

객체가 모두 사용자 고유의 유형인 경우__lt__()다른 물건과 비교하는 방법을 알 수 있도록 말이죠.그럼 그냥 분류하면 되겠네요.key=파라미터를 지정합니다.물론, 그 정의도 할 수 있습니다.__hash__()및 사용Counter그게 더 빠를 거야

비교가 테스트 컨텍스트에서 수행될 경우 다음을 사용합니다(py>=3.2( ) 및 ( )2.7<=py<3.2).

캐시할 수 없는 개체의 시퀀스에서도 작동합니다.

목록에 해시할 수 없는 항목(개체 목록 등)이 포함되어 있는 경우 다음과 같은 카운터 클래스 및 id() 함수를 사용할 수 있습니다.

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

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

해시 가능 상태로 만들거나 정렬할 필요가 없습니다.

당신의 경우 아래 코드 조각이 효과가 있기를 바랍니다.

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

이렇게 하면 양쪽 목록의 모든 요소가a&b순서와 관계없이 동일합니다.

자세한 내용은 이 질문의 답변을 참조하십시오.

목록을 비교하는 함수를 직접 작성할 수 있습니다.

두 개의 목록을 얻읍시다.

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

데이터가 정렬되지 않은 경우 정렬이 매우 느릴 수 있습니다(항목의 순서가 일정 수준일 경우 시간 정렬이 특히 좋습니다.또한 둘 다 정렬하려면 두 목록을 모두 완전히 반복해야 합니다.

목록을 변환하는 것이 아니라 세트를 할당하고 왼쪽 멤버십 체크를 수행합니다.그 동안 각 항목이 몇 개 존재하는지 카운트합니다.

  • 두 목록의 길이가 동일하지 않은 경우 단락했다가 반환할 수 있습니다.False지금 당장.
  • 내의 했을 경우ab할 수 있다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

언급URL : https://stackoverflow.com/questions/7828867/how-to-efficiently-compare-two-unordered-lists-not-sets

반응형