1. 程式人生 > >scala把序列分解成子集(group by,partition)

scala把序列分解成子集(group by,partition)

Problem

    你想要基於一種演算法或者規則,把一個序列切分為兩個或者多個子集。

Solution

    使用groupBy,partition,span,splitAt方法可以把一個集合切分成子集合。sliding和unzip方法也可以用來把集合切分成子集合,儘管sliding可以產生許多子序列,unzip則主要用來拆分二元祖。

    groupy,partition和span方法可以讓你把一個集合按一個方法定義切分成子集合,splitAt讓你按集合下標切分一個集合為兩個子集合:

scala> val x = List(1510582012)
x: List
[Int] = List(1510582012)
scala> x.groupBy(_ > 10)
res19: scala.collection.immutable.Map[Boolean,List[Int]] = Map(false -> List(1058), true -> List(152012))

scala> x.partition(_ > 10)
res20: (List[Int], List[Int]) = (List(152012),List(1058))

scala> x.partition(_ > 10
) res20: (List[Int], List[Int]) = (List(152012),List(1058)) scala> x.span(_ < 20) res21: (List[Int], List[Int]) = (List(151058),List(2012)) scala> x.splitAt(2) res22: (List[Int], List[Int]) = (List(1510),List(582012))

    groupBy(p)方法會把一個集合根據你提供的方法切分成一個map。Map中key=true對應的value是所有使p返回true的集合元素組成的新集合,key=flase對應的value是所有使p返回false的元素組成的新集合。

    方法partition(p),span(p)和splitAt(n)會建立一個二元祖,二元祖的每個元素都是和原集合型別相同的集合。partiton會把集合的所有元素遍歷一遍,滿足條件p的元素進二元祖第一個集合,不滿足條件p的元素進二元祖第二個集合。span方法會從集合頭部開始遍歷直到第一個不滿足p的元素為止,所有滿足p的進第一個集合,不滿足p的進第二個集合。splitAt可以認為前n個元素進第一個集合,剩餘元素進第二個集合。

    我們可以用下面這種方式來接收返回值:

scala> val (a,b) = x.partition(_ > 10)
a: List[Int] = List(152012)
b: List[Int] = List(1058)

scala> a
res23: List[Int] = List(152012)

scala> b
res24: List[Int] = List(1058)

    我們可以用下面的形式接收groupBy方法的返回值:

scala> val groups = x.groupBy(_ > 10)
groups: scala.collection.immutable.Map[Boolean,List[Int]] = Map(false -> List(1058), true -> List(152012))

scala> val trues = groups(true)
trues: List[Int] = List(152012)

scala> val falses = groups(false)
falses: List[Int] = List(1058)

    視窗方法sliding(w,s),w是視窗大小,s是每次滑動距離。使用這個方法,就是下標從0開始,每次向後移動s距離,每次取當前下標開始的w個元素,組成一個新的集合。

scala> val nums = (1 to 5).toArray
nums: Array[Int] = Array(12345)

scala> nums.sliding(2)
res25: Iterator[Array[Int]] = non-empty iterator

scala> nums.sliding(2).toList
res26: List[Array[Int]] = List(Array(12), Array(23), Array(34), Array(45))

scala> nums.sliding(2,2).toList
res27: List[Array[Int]] = List(Array(12), Array(34), Array(5))

scala> nums.sliding(2,3).toList
res28: List[Array[Int]] = List(Array(12), Array(45))

    unzip方法處理二元祖集合,它可以把二元祖裡的第一個元素歸為一個集合,二元祖裡的第二個元素歸為第二個集合:

scala> val listOfTuple2s = List((1,2), ('a''b'))
listOfTuple2s: List[(AnyVal, AnyVal)] = List((1,2), (a,b))

scala> val x = listOfTuple2s.unzip
x: (List[AnyVal], List[AnyVal]) = (List(1, a),List(2, b))

    下面這個例子中,我們使用unzip方法來把couples集合中丈夫和妻子分到兩個集合中:

scala> val couples = List(("Kim""Al"), ("Julia""Terry"))
couples: List[(String, String)] = List((Kim,Al), (Julia,Terry))

scala> val (women, men) = couples.unzip
women: List[String] = List(Kim, Julia)
men: List[String] = List(Al, Terry)

    unzip正好是zip的反方法:

scala> List(1,2,3).zip(List(4,5,6))
res30: List[(Int, Int)] = List((1,4), (2,5), (3,6))

scala> List(1,2,3).zip(List(4,5,6)).unzip
res31: (List[Int], List[Int]) = (List(123),List(456))