2

Martin Odersky gives this example to split out an array into 2 collections:

val people: Array[Person]
val (minors, adults) = people partition (_.age < 18)

class Person(val name: String, val age: Int)

What is the best way to split out into 3 or more arrays:

val (minors, adults, seniors) = people partition?? x < 18, 18 < x < 65, x > 65 // ?

4

4 回答 4

7

用单线做这件事可能不太漂亮。

val (minors, older) = people partition {_.age < 18}
val (adults, seniors) = older partition {_.age < 65}    
于 2012-07-09T22:17:47.843 回答
3
def multiPartition[T: Manifest](xs: Traversable[T])(fs: T => Boolean *) = {
  val builders = Vector.fill(fs.length)(ArrayBuffer.empty[T])
  for (e <- xs) {
    val i = fs.indexWhere(f => f(e))
    if (i >= 0) builders(i) += e
  }
  builders.map(_.toArray)    
}

示例用法是:

val Seq(minors, adults, seniors) = 
    multiPartition(people)(_.age < 18, _.age < 65, _ => true)

所以第二个 arg 列表中的每个术语都是一个“桶”,_ => true是“其他所有”。

这将返回数组。我做了一个非常相似的版本,在这里吐出你原来的集合类型,虽然我不知道如何让它也适用于数组。

于 2012-07-10T00:35:15.943 回答
2

这将返回一个 Tuple3,就像您在关于未成年人、成年人和老年人的问题中所说的那样。不过,可能有一种更有效和更通用的方法。

Tuple3(people.filter(_.age < 18), people.filter(p => p.age > 18 && p.age < 65), people.filter(_.age > 65))

于 2012-07-09T23:00:11.353 回答
2

您可以使用 groupBy 方法:

case class Person(name: String, age: Int)

val people = Array(Person("A",1),Person("B",2),Person("C",14),Person("D",19),Person("E",70))

def typeByAge(p: Person): String = 
  if(p.age < 4) "BABY"
  else if(p.age < 18) "MINOR"
  else if(p.age < 65) "ADULT"
  else "OLD"

val g = people groupBy typeByAge

val (babys,minors,adults,olds) = (g("BABY"),g("MINOR"),g("ADULT"),g("OLD"))
于 2012-07-10T01:16:49.093 回答