Ryan is an engineer in the Sacramento Area with a focus in Python, Ruby, and Rust. Bash/Python Exercism mentor. Coding, physics, calculus, music, woodworking. Looking for work!
Finishing this one up a little late, but it's my second one completed today, so I'm catching back up! Lots of sets, but pretty straightforward once I figured out how you could possibly even rule things in or out for sure. The code came out simpler than I expected.
"""Day 21: Allergen Assessment
Find out through process of elimination which foreign ingredients
contain which allergens.
"""fromcollectionsimportCounterdefparse(filename):"""Parse the input file into Python objects.
Input file has lines like this:
sdfsjdfk sjdkf lfke ljrl (contains dairy, soy)
Parameters:
filename (str): the name of the input file to open
Returns:
candidates (Dict[str, Set[str]]): a dict with keys that are the
allergens (dairy, soy, etc.) and values that are the sets
of all possible ingredients that could contain those
allergens.
counts (Counter): a count of how many lines each ingredient
appears in.
"""candidates=dict()counts=Counter()withopen(filename,"r")asf:forlineinf:ingredients,_contains,allergens=line.partition(" (contains ")ingredients=set(ingredients.split())counts+=Counter(ingredients)forallergeninallergens.strip(")\n").split(", "):ifallergenincandidates:candidates[allergen]&=ingredientselse:candidates[allergen]=ingredients.copy()returncandidates,countsdeffind_allergens(candidates):"""Uses allergens that only have one possible ingredient that could
contain them to rule that ingredient out for other allergens until
all allergens have exactly one ingredient that could contain it.
Returns a dict of allergen name to ingredient name to simplify things.
"""whilenotall(len(ingredients)==1foringredientsincandidates.values()):forallergen,ingredientsincandidates.items():iflen(ingredients)==1:forother_al,other_ingredientsincandidates.items():ifother_al!=allergen:other_ingredients-=ingredientsreturn{allergen:ingredients.pop()forallergen,ingredientsincandidates.items()}defdiscard_unsafe_ingredient_counts(allergens,counts):"""Given a set of decided allergens, removes each of these unsafe
ingredients from a dict of counts so that only the counts of totally
safe ingredients are retained.
"""foringredientinallergens.values():delcounts[ingredient]defpart1(counts):"""Part 1 asks us to add up the number of occurrences of any totally
safe ingredient.
Assumes `counts` has already had its unsafe ingredients discarded.
"""returnsum(counts.values())defpart2(allergens):"""Part 2 wants the list of unsafe ingredients, sorted by their
allergen alphabetically, joined together into one string by commas.
"""return",".join(ingredientfor(allergen,ingredient)insorted(allergens.items()))if__name__=="__main__":test_candidates,test_counts=parse("data/day21_test.txt")test_allergens=find_allergens(test_candidates)discard_unsafe_ingredient_counts(test_allergens,test_counts)assert5==part1(test_counts)assert"mxmxvkd,sqjhc,fvjkl"==part2(test_allergens)print("All tests passed!")candidates,counts=parse("data/day21.txt")allergens=find_allergens(candidates)discard_unsafe_ingredient_counts(allergens,counts)print("Part 1:",part1(counts))print("Part 2:",part2(allergens))
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Finishing this one up a little late, but it's my second one completed today, so I'm catching back up! Lots of sets, but pretty straightforward once I figured out how you could possibly even rule things in or out for sure. The code came out simpler than I expected.