A も B も複数の範囲を指定できるようにしたので、
1つの場合でも ( ) をつけて tuple にしないといけません。
というのが最初のコードでしたが、その問題を修正しました。
Python
1defrange_sub(a, b):2iflen(a)==0orlen(b)==0:return[]3iftype(a[0])!=tuple: a =[tuple(a)]4iftype(b[0])!=tuple: b =[tuple(b)]5 c =[]6for t in a:7 c.append([t[0],2])8 c.append([t[1],3])9for t in b:10 c.append([t[0],1])11 c.append([t[1],4])12 c.sort();13 aa = bb =False14 d =[]15for t in c:16if t[1]==2:17ifnot aa andnot bb: d.append(t[0])18 aa =True19elif t[1]==3:20if aa andnot bb: d.append(t[0])21 aa =False22elif t[1]==1:23ifnot bb and aa: d.append(t[0])24 bb =True25else:26if bb and aa: d.append(t[0])27 bb =False28 c =[]29for i inrange(0,len(d),2):30 c.append((d[i], d[i+1]))31iflen(c)==1: c =[c[0][0], c[0][1]]32return c
333435a =["2021/08/23 12:00:00","2021/08/23 18:00:00"]36b =["2021/08/23 13:00:00","2021/08/23 14:00:00"]37c = range_sub(a, b)38print(a)39print(b)40print(c)41print()4243a =["2021/08/23 12:00:00","2021/08/23 18:00:00"]44b =[("2021/08/23 13:00:00","2021/08/23 14:00:00"),("2021/08/23 17:00:00","2021/08/23 21:00:00")]45c = range_sub(a, b)46print(a)47print(b)48print(c)49print()5051a =["2021/08/23 12:00:00","2021/08/23 18:00:00"]52b =["2021/08/23 19:00:00","2021/08/23 20:00:00"]53c = range_sub(a, b)54print(a)55print(b)56print(c)57
1from functools importreduce23# Subtract Overlaps Between Two Ranges Without Sets4# https://stackoverflow.com/questions/6462272/subtract-overlaps-between-two-ranges-without-sets5# https://stackoverflow.com/a/64627316classIntervalTree:7def__init__(self, h, left, right):8 self.h = h
9 self.left = left
10 self.right = right
1112defmerge(A, B, op, l=-float("inf"), u=float("inf")):13if l > u:14returnNone15ifnotisinstance(A, IntervalTree):16ifisinstance(B, IntervalTree):17 opT = op
18 A, B, op = B, A,(lambda x, y : opT(y,x))19else:20return op(A, B)21 left = merge(A.left, B, op, l,min(A.h, u))22 right = merge(A.right, B, op,max(A.h, l), u)23if left isNone:24return right
25elif right isNoneor left == right:26return left
27return IntervalTree(A.h, left, right)2829defto_range_list(T, l=-float("inf"), u=float("inf")):30ifisinstance(T, IntervalTree):31return to_range_list(T.left, l, T.h)+ to_range_list(T.right, T.h, u)32#return [(l, u-1)] if T else [] # -33return[(l, u)]if T else[]# +3435defrange_list_to_tree(L):36returnreduce(lambda x, y : merge(x, y,lambda a, b: a or b),37#[ IntervalTree(R[0], False, IntervalTree(R[1]+1, True, False)) for R in L ]) # -38[ IntervalTree(R[0],False, IntervalTree(R[1],True,False))for R in L ])# +3940# helper function41defget_interval_list( A, B):42 r1 = range_list_to_tree(A)43 r2 = range_list_to_tree(B)44 diff = merge(r1, r2,lambda a, b : a andnot b)45return to_range_list(diff)4647A =[(12,18)]48B =[(13,14)]49ret = get_interval_list( A, B)50print(ret)# [(12, 13), (14, 18)]5152A =[(12,18)]53B =[(13,14),(17,21)]54ret = get_interval_list( A, B)55print(ret)# [(12, 13), (14, 17)]