只是想用一个“更通用”的版本来扩展 mkneissl 的答案,该版本应该适用于库中的许多不同集合:
scala> import collection._
import collection._
scala> import generic.CanBuildFrom
import generic.CanBuildFrom
scala> def partition[X,A,B,CC[X] <: Traversable[X], To, To2](xs : CC[X])(f : X => Either[A,B])(
| implicit cbf1 : CanBuildFrom[CC[X],A,To], cbf2 : CanBuildFrom[CC[X],B,To2]) : (To, To2) = {
| val left = cbf1()
| val right = cbf2()
| xs.foreach(f(_).fold(left +=, right +=))
| (left.result(), right.result())
| }
partition: [X,A,B,CC[X] <: Traversable[X],To,To2](xs: CC[X])(f: (X) => Either[A,B])(implicit cbf1: scala.collection.generic.CanBuildFrom[CC[X],A,To],implicit cbf2: scala.collection.generic.CanBuildFrom[CC[X],B,To2])(To, To2)
scala> partition(List(1,"two", 3)) {
| case i: Int => Left(i)
| case x => Right(x)
| }
res5: (List[Int], List[Any]) = (List(1, 3),List(two))
scala> partition(Vector(1,"two", 3)) {
| case i: Int => Left(i)
| case x => Right(x)
| }
res6: (scala.collection.immutable.Vector[Int], scala.collection.immutable.Vector[Any]) = (Vector(1, 3),Vector(two))
注意一点:分区方法类似,但我们需要捕获几种类型:
X -> 集合中项目的原始类型。
A -> 左分区的项目类型
B -> 右分区的项目类型
CC -> 集合的“特定”类型(Vector、List、Seq 等)必须是更高种类的。我们可能可以解决一些类型推断问题(请参阅此处 Adrian 的回复:http://suereth.blogspot.com/2010/06/preserving-types-and-differing-subclass.html),但我感觉很懒;)
To -> 左侧集合的完整类型
To2 -> 右侧集合的完整类型
最后,有趣的“CanBuildFrom”隐式参数使我们能够通用地构造特定类型,如 List 或 Vector。它们内置于所有核心库集合中。
具有讽刺意味的是,CanBuildFrom 魔法的全部原因是正确处理 BitSet。因为我要求 CC 更高级,所以我们在使用分区时会收到这个有趣的错误消息:
scala> partition(BitSet(1,2, 3)) {
| case i if i % 2 == 0 => Left(i)
| case i if i % 2 == 1 => Right("ODD")
| }
<console>:11: error: type mismatch;
found : scala.collection.BitSet
required: ?CC[ ?X ]
Note that implicit conversions are not applicable because they are ambiguous:
both method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]
and method any2Ensuring in object Predef of type [A](x: A)Ensuring[A]
are possible conversion functions from scala.collection.BitSet to ?CC[ ?X ]
partition(BitSet(1,2, 3)) {
如果需要,我将把它留给别人修复!再玩一会儿,我看看能否给你一个适用于 BitSet 的解决方案。