scala把序列分解成子集(group by,partition)
Problem
你想要基於一種演算法或者規則,把一個序列切分為兩個或者多個子集。
Solution
使用groupBy,partition,span,splitAt方法可以把一個集合切分成子集合。sliding和unzip方法也可以用來把集合切分成子集合,儘管sliding可以產生許多子序列,unzip則主要用來拆分二元祖。
groupy,partition和span方法可以讓你把一個集合按一個方法定義切分成子集合,splitAt讓你按集合下標切分一個集合為兩個子集合:
scala> val x = List(15, 10, 5, 8, 20, 12)
x: List [Int] = List(15, 10, 5, 8, 20, 12)
scala> x.groupBy(_ > 10)
res19: scala.collection.immutable.Map[Boolean,List[Int]] = Map(false -> List(10, 5, 8), true -> List(15, 20, 12))
scala> x.partition(_ > 10)
res20: (List[Int], List[Int]) = (List(15, 20, 12),List(10, 5, 8))
scala> x.partition(_ > 10 )
res20: (List[Int], List[Int]) = (List(15, 20, 12),List(10, 5, 8))
scala> x.span(_ < 20)
res21: (List[Int], List[Int]) = (List(15, 10, 5, 8),List(20, 12))
scala> x.splitAt(2)
res22: (List[Int], List[Int]) = (List(15, 10),List(5, 8, 20, 12))
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(15, 20, 12)
b: List[Int] = List(10, 5, 8)
scala> a
res23: List[Int] = List(15, 20, 12)
scala> b
res24: List[Int] = List(10, 5, 8)
我們可以用下面的形式接收groupBy方法的返回值:
scala> val groups = x.groupBy(_ > 10)
groups: scala.collection.immutable.Map[Boolean,List[Int]] = Map(false -> List(10, 5, 8), true -> List(15, 20, 12))
scala> val trues = groups(true)
trues: List[Int] = List(15, 20, 12)
scala> val falses = groups(false)
falses: List[Int] = List(10, 5, 8)
視窗方法sliding(w,s),w是視窗大小,s是每次滑動距離。使用這個方法,就是下標從0開始,每次向後移動s距離,每次取當前下標開始的w個元素,組成一個新的集合。
scala> val nums = (1 to 5).toArray
nums: Array[Int] = Array(1, 2, 3, 4, 5)
scala> nums.sliding(2)
res25: Iterator[Array[Int]] = non-empty iterator
scala> nums.sliding(2).toList
res26: List[Array[Int]] = List(Array(1, 2), Array(2, 3), Array(3, 4), Array(4, 5))
scala> nums.sliding(2,2).toList
res27: List[Array[Int]] = List(Array(1, 2), Array(3, 4), Array(5))
scala> nums.sliding(2,3).toList
res28: List[Array[Int]] = List(Array(1, 2), Array(4, 5))
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(1, 2, 3),List(4, 5, 6))