Scala 中基于类型的集合分区 [英] Type based collection partitioning in Scala

查看:24
本文介绍了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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆