2012-07-09 20 views
2

馬丁·奧德斯基給出了這樣的例子,以分割出的陣列分成2個集合:分裂出3個或更多陣列Scala中

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

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

什麼是拆分到3個或更多個陣列的最佳方式:

val(未成年人,成年人,老年人)=人分區x < 18,18 < x < 65,x> 65 //?

回答

7

這樣做只用一行就可能不那麼漂亮。

val (minors, older) = people partition {_.age < 18} 
val (adults, seniors) = older partition {_.age < 65}  
2

這將返回一個Tuple3像你在未成年人,成年人和老年人問題中注意到的。儘管如此,可能有更高效和更普遍的方法。

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

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是 「一切」。這個返回數組。我做了一個非常類似的版本,吐出你原來的收集類型here,雖然我不知道如何得到這個工作陣列。

+0

這是我更容易推理的一般多分區作爲應用相互排斥的過濾功能,可以實現'一個集合(F < - FS)產量xs.filter(f)'。它的速度比較慢,因爲對於每個過濾器fs都會過濾收集的xs。 – Brian 2012-07-10 04:35:03

+0

@Brian如果條件重疊,那麼它的工作方式與上述不同。我的實現將元素添加到滿足條件的第一個存儲桶中。它應該如何工作是有爭議的,但我選擇這種方式是因爲對我來說,「分區」表明一組元素分裂而不是重複。它的優點是,你可以很容易地擁有一個「其他所有」的身份桶,而不是定義一個額外的功能作爲所有其他功能的否定。 – 2012-07-10 05:01:31

+0

同意。這就是爲什麼我注意到過濾器必須互相排斥或者有重疊。 – Brian 2012-07-10 05:04:45

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"))