Skip to content

Instantly share code, notes, and snippets.

@waynejo
Last active May 21, 2021 12:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save waynejo/db28ae717333462f803a8cb02f5fc7b2 to your computer and use it in GitHub Desktop.
Save waynejo/db28ae717333462f803a8cb02f5fc7b2 to your computer and use it in GitHub Desktop.
import java.io.FileInputStream
import scala.io.StdIn
type Allergen = String
type Ingredient = String
case class FoodListElement(ingredient: Vector[Ingredient], allergen: Vector[Allergen]) {
def allergenMap(): Map[Allergen, Set[Ingredient]] = {
ingredient.foldLeft(Map[Allergen, Set[Ingredient]]()) { (acc, ingredient) =>
allergen.foldLeft(acc) { (subAcc, allergen) =>
subAcc.updated(allergen, subAcc.getOrElse(allergen, Set()) + ingredient)
}
}
}
}
def removeRedundant(availables: Map[Allergen, Set[Ingredient]]): Map[Allergen, Set[Ingredient]] = {
val determined = availables.filter(1 == _._2.size).map(_._2.toIterable.head).toSet
val nextAvailables = availables.view.mapValues(v => {
if 1 == v.size then
v
else
v.filter(!determined.contains(_))
}).toMap
if availables == nextAvailables then
availables
else
removeRedundant(nextAvailables)
}
def findAllergenIngredient(availables: Map[Allergen, Set[Ingredient]], unkowns: Vector[FoodListElement]): Map[Allergen, Ingredient] = {
unkowns.headOption match {
case Some(foodListElement) =>
val allergens = foodListElement.allergenMap()
val nextAvailables = allergens.foldLeft(availables) { (acc, kv) =>
val newOnes = kv._2
acc.updated(kv._1, acc.get(kv._1).map { _.intersect(newOnes) }.getOrElse(newOnes))
}
findAllergenIngredient(nextAvailables, unkowns.tail)
case _ =>
removeRedundant(availables).filter(1 == _._2.size).view.mapValues(_.toIterable.head).toMap
}
}
def solve1(foodList: Vector[FoodListElement]): Int = {
val allergens = findAllergenIngredient(Map(), foodList).values.toSet
foodList.flatMap(_.ingredient).count(ingredient => !allergens.contains(ingredient))
}
def solve2(foodList: Vector[FoodListElement]): String = {
val allergens = findAllergenIngredient(Map(), foodList).toVector
allergens.sortBy(_._1).map(_._2).mkString(",")
}
@main def solve21() =
val in = new FileInputStream("example21-1.in")
System.setIn(in)
val inputs = Iterator.continually(StdIn.readLine()).takeWhile(_ != null).toVector
val foodList = inputs.map { line =>
val worlds = line.split("[\\(\\)]").filter(_.nonEmpty)
val ingredients = worlds.head.split(" ").filter(_.nonEmpty).toVector
val allergens = worlds.last.split("[, ]").filter(_.nonEmpty).toVector.tail
FoodListElement(ingredients, allergens)
}
println(solve1(foodList)) // 2517
println(solve2(foodList)) // rhvbn,mmcpg,kjf,fvk,lbmt,jgtb,hcbdb,zrb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment