Scala 中基于类型的集合分区 [英] Type based collection partitioning in Scala
问题描述
给定以下数据模型:
sealed trait Fruit
case class Apple(id: Int, sweetness: Int) extends Fruit
case class Pear(id: Int, color: String) extends Fruit
我一直在寻找实现一个分离篮子函数,对于给定的水果篮子,它会返回单独的苹果和梨篮子:
I've been looking to implement a segregate basket function which for the given basket of fruits will return separate baskets of apples and pears:
def segregateBasket(fruitBasket: Set[Fruit]): (Set[Apple], Set[Pear])
我尝试了几种方法,但似乎没有一种方法完全符合要求.以下是我的尝试:
I've attempted a couple of approaches, but none of them seems to be fitting the bill perfectly. Below are my attempts:
def segregateBasket1(fruitBasket: Set[Fruit]): (Set[Apple], Set[Pear]) = fruitBasket
.partition(_.isInstanceOf[Apple])
.asInstanceOf[(Set[Apple], Set[Pear])]
这是我找到的最简洁的解决方案,但会受到通过 asInstanceOf
进行显式类型转换的影响,如果我决定添加其他类型的水果,扩展起来会很痛苦.因此:
This is the most concise solution I've found, but suffers from explicit type casting via asInstanceOf
and is going to be a pain to extend should I decide to add additional types of fruits. Therefore:
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".因此:
Resolves the problem of additional fruit types (extension really easy), but still strongly depends on risky type casting 'asInstanceOf' which I'd rather avoid. Therefore:
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)
}
解决了显式转换的问题,但使用可变集合,理想情况下我想坚持使用不可变集合和惯用代码.
Resolves the problem of explicit casting, but uses mutable collections and ideally I'd like to stick with immutable collections and idiomatic code.
我在这里查看:Scala:基于类型过滤以获得一些灵感,但也找不到更好的方法.
I've looked here: Scala: Filtering based on type for some inspiration, but couldn't find a better approach either.
有人对如何在 Scala 中更好地实现此功能有任何建议吗?
Does anyone have any suggestions on how this functionality can be better implemented in Scala?
推荐答案
val emptyBaskets: (List[Apple], List[Pear]) = (Nil, Nil)
def separate(fruits: List[Fruit]): (List[Apple], List[Pear]) = {
fruits.foldRight(emptyBaskets) { case (f, (as, ps)) =>
f match {
case a @ Apple(_, _) => (a :: as, ps)
case p @ Pear(_, _) => (as, p :: ps)
}
}
}
这篇关于Scala 中基于类型的集合分区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!