Учитывая следующую модель данных:
sealed trait Fruit
case class Apple(id: Int, sweetness: Int) extends Fruit
case class Pear(id: Int, color: String) extends Fruit
Я искал реализацию отдельной функции корзины, которая для данной корзины фруктов вернет отдельные корзины из яблок и груш:
def segregateBasket(fruitBasket: Set[Fruit]): (Set[Apple], Set[Pear])
Я попытался сделать несколько подходов, но ни один из них, похоже, не подгоняет счет. Ниже приведены мои попытки:
def segregateBasket1(fruitBasket: Set[Fruit]): (Set[Apple], Set[Pear]) = fruitBasket
.partition(_.isInstanceOf[Apple])
.asInstanceOf[(Set[Apple], Set[Pear])]
Это наиболее сжатое решение, которое я нашел, но страдает от явного ввода типов через asInstanceOf
и будет больно, если я решит добавить дополнительные типы фруктов. Поэтому:
def segregateBasket2(fruitBasket: Set[Fruit]): (Set[Apple], Set[Pear]) = {
val mappedFruits = fruitBasket.groupBy(_.getClass)
val appleSet = mappedFruits.getOrElse(classOf[Apple], Set()).asInstanceOf[Set[Apple]]
val pearSet = mappedFruits.getOrElse(classOf[Pear], Set()).asInstanceOf[Set[Pear]]
(appleSet, pearSet)
}
Решает проблему дополнительных типов фруктов (расширение очень простое), но все еще сильно зависит от рискованного типа "asInstanceOf", которого я бы предпочел избежать. Поэтому:
def segregateBasket3(fruitBasket: Set[Fruit]): (Set[Apple], Set[Pear]) = {
val appleSet = collection.mutable.Set[Apple]()
val pearSet = collection.mutable.Set[Pear]()
fruitBasket.foreach {
case a: Apple => appleSet += a
case p: Pear => pearSet += p
}
(appleSet.toSet, pearSet.toSet)
}
Устанавливает проблему явного литья, но использует изменчивые коллекции, и в идеале я хотел бы придерживаться неизменных коллекций и идиоматического кода.
Я смотрел здесь: Scala: Фильтрация по типу для какого-то вдохновения, но не могла найти лучшего подхода.
Есть ли какие-либо предложения о том, как эта функциональность может быть лучше реализована в Scala?