def main(): with open("input.txt") as f: lines = f.read().split('\n') foods = [s[:-1].split(' (contains ') for s in lines] # map allergens to possible ingredients possible = [ (allergen, set(food[0].split(' '))) for food in foods for allergen in food[1].split(', ') ] # get sets of all allergens and all ingredients allergens = {p[0] for p in possible} ingredients = set.union(*[p[1] for p in possible]) # find which ingredients are always listed for a given allergen possible = { a:set.intersection(*[ s[1] for s in possible if s[0] == a] ) for a in allergens } # reduce while any({i for i in possible if len(possible[i]) > 1}): for b in {j for j in possible if len(possible[j]) > 1}: for a in {i for i in possible if len(possible[i]) == 1}: possible[b] -= possible[a] # find sets of allergenic and non-allergenic unsafe = set.union(*list(possible.values())) safe = ingredients - unsafe # print('|non-allergen occurrences| =', sum( food[0].split().count(s) for food in foods for s in safe) ) print('allergens:', ','.join( [ list(possible[a])[0] for a in sorted(list(possible)) ]) ) """ all_ingredients = set() all_allergens = set() may_contain = {} unsafe_ingredients = {} foods = [] for line in lines: ingredients, contains = line.split(' (contains ') ingredients = ingredients.split(' ') contains = contains[:-1].split(', ') # remove trailing ")" then split all_ingredients = all_ingredients | set(ingredients) all_allergens = all_allergens | set(contains) """ if __name__ == "__main__": main()