def parse(input): ranges = [] ids = [] with open(input) as f: for line in f: line = line.strip() if line == "": break lo, _, hi = line.partition("-") ranges.append((int(lo), int(hi))) for line in f: ids.append(int(line.strip())) return ranges, ids def solve(input): # Part 1: count the number of given ids which are within one of the ranges ranges, ids = parse(input) t = 0 for x in ids: for lo,hi in ranges: if lo <= x <= hi: t += 1 break print(t) # Part 2: count the number of possible ids which are within one of the ranges -- # in other words, the size of the union of all the ranges. # # We start by flattening the ranges so that they don't overlap with each other flattened = [] queue = list(ranges) while queue: lo, hi = queue.pop() found = False for i,(x,y) in enumerate(flattened): if not (hi < x or y < lo): found = True break if found: #print("collapsing ({:,} {:,}) and ({:,} {:,}) -> ({:,} {:,})".format(x,y,lo,hi,min(x,lo),max(y,hi))) # if x <= lo <= hi < y then the range is unchanged and we don't need to update flattened[i]. # otherwise we need to add the new range to the queue to see if it can be merged with any other entries. if lo < x or hi > y: del flattened[i] queue.append((min(x,lo), max(y,hi))) else: flattened.append((lo,hi)) # Then we sum up their sizes. Ranges are inclusive, so +1. t = 0 for x,y in flattened: t += y-x + 1 print(t) solve("sample") solve("input")