2016-06-01 2 views
0

과 현명한이 반복 가능 객체 요소를 비교 내가 다르게 각각의 경우를 현명 두 개의 정렬 된 목록 요소를 비교하고 처리하고 싶습니다 :파이썬 : 다른 종류의

  1. 을 모두 반복 가능 객체는 요소를 포함하는 경우에, 나는 전화를하고 싶습니다 update_func.
  2. 왼쪽 반복 만 요소가 포함되어있는 경우 left_surplus_func으로 문의하십시오.
  3. 올바른 반복 가능 요소에만 요소가 포함되어있는 경우 right_surplus_func으로 전화하고 싶습니다.

불행히도, 관련없는 요소의 튜플을 생성하기 때문에 zip은이 경우 도움이되지 않습니다. 또한 필자의 경우리스트 또는 iterable은 서로 다른 유형이며 서로 변환 할 수없는 유형이다.

이것은 How can I compare two lists in python and return matchesChecking if any elements in one list are in another과 유사하지만 실제 해결책이 될만큼 근접하지는 않습니다.

나는 (None를 포함 할 수 없습니다 모두 반복 가능 객체 제외) 작업 솔루션 함께했다 :

def compare_iterables_elemet_wise(left, right, compare_func, 
          left_surplus_func, update_func, right_surplus_func): 
    """ 
    :type left: collections.Iterable[U] 
    :type right: collections.Iterable[T] 
    :type compare_func: (U, T) -> int 
    :type left_surplus_func: (U) -> None 
    :type update_func: (U, T) -> None 
    :type right_surplus_func: (T) -> None 
    """ 
    while True: 
     try: 
      l = next(left) 
     except StopIteration: 
      l = None # Evil hack, but acceptable for this example 
     try: 
      r = next(right) 
     except StopIteration: 
      r = None 

     if l is None and r is not None: 
      cmp_res = 1 
     elif l is not None and r is None: 
      cmp_res = -1 
     elif l is None and r is None: 
      return 
     else: 
      cmp_res = compare_func(l, r) 

     if cmp_res == 0: 
      update_func(l, r) 
     elif cmp_res < 0: 
      left_surplus_func(l) 
      right = itertools.chain([r], right) # aka right.unget(r) 
     else: 
      right_surplus_func(r) 
      left = itertools.chain([l], left) # aka left.unget(l) 

비슷한 결과를 보관하기보다 파이썬 방법이 있나요? 나는 함수의 외부 부작용에 의존하기 때문에 내 솔루션에 조금 불만 스럽다. 순수한 기능적 솔루션을 갖는 것이 좋을 것입니다.

편집 : creates, updatesdeletes : 난 그냥이 세 가지 목록을 필요

creates = [] 
updates = [] 
deletes = [] 

def compare(a, obj): 
    return cmp(int(a), obj) 

def handle_left(a): 
    creates.append(a) 

def update(a, obj): 
    updates.append((a, obj)) 

def handle_right(obj): 
    deletes.append(obj) 

left = list('12356') 
right = [1, 3, 4, 6, 7] 
compare_iterables_elemet_wise(iter(left), iter(right), compare, handle_left, update, handle_right) 

assert creates == ['2', '5'] 
assert updates == [('1', 1), ('3', 3), ('6', 6)] 
assert deletes == [4, 7] 

내가 추측에는 요 : 이것은 내 테스트 케이스이다.

Edit2가 : 설정 작업 : 왼쪽과 오른쪽의 종류가 다른 것을 제외하고

이, 내 문제와 유사하다 :

left = [1, 2, 3, 5, 6] 

right = [1, 3, 4, 6, 7] 

In [10]: set(left) - set(right) 
Out[10]: {2, 5} 

In [11]: set(right) - set(left) 
Out[11]: {4, 7} 


In [14]: set(right).intersection(set(left)) 
Out[14]: {1, 3, 6} 
+0

은 같은 길이의 두 목록입니까? 네 문제에 따라 아니 겠지? 특정 코드 대신 간단한 일반 예제를 제공하면 도움이 될 것입니다. –

+0

@ColonelBeauvel : 여기 있습니다. –

+1

당신이 성취하려고 시도하는 것이 내 관점에서 명백하지 않습니다 ... 목록 사이의 그러한 세트 차이 (변환 후)가 당신의 문제에 도움이 될 수 있습니까? –

답변

1

당신은의 시작에 try 문을 단순화 할 수 있습니다 while 루프는 기본 인수 인 next 내장 함수를 사용합니다.

def compare_iterables_element_wise(left, right, compare_func, 
         left_surplus_func, update_func, right_surplus_func): 

    l, r = next(left, None), next(right, None) 
    while l or r: 
     if l is None and r is not None: 
      cmp_res = 1 
     elif l is not None and r is None: 
      cmp_res = -1 
     else: 
      cmp_res = compare_func(l, r) 

     if cmp_res == 0: 
      update_func(l, r) 
      l, r = next(left, None), next(right, None) 
     elif cmp_res < 0: 
      left_surplus_func(l) 
      l = next(left, None) 
     else: 
      right_surplus_func(r) 
      r = next(right, None) 

는 또한 인수 중 하나가 첫 번째 if 없애 너무 None입니다 compare_func이 사건을 처리하는 건의 할 것입니다.

두 번째 편집에서 개체 집합을 일반적인 형식으로 변환 할 수 있다면 집합을 사용하는 것이 좋습니다. __hash__ 메서드를 사용하여 각 개체에 정수를 연결하고 hash 값을 기반으로 작업을 수행 할 수 있습니다.