Как уменьшить каждый отдельный ингредиент в соответствии с другой последовательностью «примененных» ингредиентов в рецепте - PullRequest
1 голос
/ 17 февраля 2020

Итак, у меня есть суп, который состоит из последовательности ингредиентов. Мне нужно определить, какие ингредиенты мне еще нужно нанести на суп, исходя из последовательности смесей, которые я уже добавил к супу, который я делаю.

case class Ingredient(name: String)
case class Mixture(ingredient: Ingredient, amount: Int)

// ingredient required to make soup
val i1 = Ingredient("water")
val i2 = Ingredient("salt")
val i3 = Ingredient("sugar")

val soupRequirements = Seq(Mixture(i1, 100), Mixture(i2, 200), Mixture(i3, 50))

println(soup)


val addedIngrediants = Seq(Mixture(i1, 50), Mixture(i2, 200), Mixture(i3, 40))

def determineWhatsLeft(soupRequirements: Seq[Mixture], addedIncredients: Seq[Mixture]): Seq[Mixture] = ???

Ссылка: https://scastie.scala-lang.org/X6PIG7zYQOGuZX7zcebgRQ

Как точно можно уменьшить каждую смесь на нужное количество функциональным способом?

1 Ответ

3 голосов
/ 17 февраля 2020

Сначала определите способ уменьшения двух Mixture с помощью инфиксного оператора

implicit class ReduceMixtures(a: Mixture) {
  def +(b: Mixture): Mixture =
    if (a.ingredient == b.ingredient) Mixture(a.ingredient, a.amount - b.amount)
    else a
}

Обратите внимание, что если ingredient s не совпадает, мы возвращаем a без изменений. Теперь мы можем реализовать determineWhatsLeft, используя foldLeft

def determineWhatsLeft(soupRequirements: Seq[Mixture], addedIncredients: Seq[Mixture]): Seq[Mixture] = {
  addedIngredients.foldLeft(soupRequirements) { case (acc, next) => acc.map(_ + next) }
}

Используя foldLeft, порядок не имеет значения, однако если бы порядок soupRequirements и addedIngredients всегда был зеркальным, то мы могли бы zip и map вот так

def determineWhatsLeft(soupRequirements: Seq[Mixture], addedIncredients: Seq[Mixture]): Seq[Mixture] =
  (soupRequirements zip addedIngredients).map { case (a, b) => a + b }

Полугруппа представляется наименее мощной абстракцией, соответствующей требованию

import cats.implicits._
import cats.Semigroup

implicit object mixtureSemigroup extends Semigroup[Mixture] {
  def combine(a: Mixture, b: Mixture): Mixture =
    if (a.ingredient == b.ingredient) Mixture(a.ingredient, a.amount - b.amount)
    else a
}

implicit object seqMixtureSemigroup extends Semigroup[Seq[Mixture]] {
  def combine(soupRequirements: Seq[Mixture], addedIncredients: Seq[Mixture]): Seq[Mixture] =
    addedIngredients.foldLeft(soupRequirements) { case (acc, next) =>
      acc.map(_ |+| next)
    }
}

soupRequirements |+| addedIngredients
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...