@@ -41,4 +41,48 @@ class SeqDecorator[C, S <: HasSeqOps[C]](coll: C)(implicit val seq: S) {
41
41
def intersperse [B >: seq.A , That ](start : B , sep : B , end : B )(implicit bf : BuildFrom [C , B , That ]): That =
42
42
bf.fromSpecificIterable(coll)(new View .IntersperseSurround (seq(coll), start, sep, end))
43
43
44
+ /** Splits this collection into groups according to the given predicate.
45
+ *
46
+ * @param p the predicate used to discriminate elements
47
+ * @return A nested collection with groups of elements,
48
+ * opening new groups whenever the predicate
49
+ * changes the return type
50
+ *
51
+ * @example {{{
52
+ * // Example 1: Split a list of integers into groups that are even / odd
53
+ * List(1, 2, 4, 6, 7).splitWith(i => i % 2 == 0) => List(List(1), List(2, 4, 6), List(7))
54
+ *
55
+ * // Example 2: Split a list of chars into groups that are upper case or lower case
56
+ * List('a', 'b', 'C', 'D', 'e', 'f').splitWith(_.isUpper) => List(List('a', 'b'), List('C', 'D'), List('e', 'f'))
57
+ * }}}
58
+ */
59
+ def splitWith [Group , That ](p : seq.A => Boolean )(implicit bfGroup : BuildFrom [C , seq.A , Group ], bfThat : BuildFrom [C , Group , That ]): That = {
60
+ def newGroupBuilder () = bfGroup.newBuilder(coll)
61
+
62
+ val groups : mutable.Builder [Group , That ] = bfThat.newBuilder(coll)
63
+ val it : Iterator [seq.A ] = seq(coll).iterator
64
+
65
+ var currentGroup = newGroupBuilder()
66
+ var lastTestResult = Option .empty[Boolean ]
67
+
68
+ while (it.hasNext) {
69
+ val elem = it.next()
70
+ val currentTest = p(elem)
71
+
72
+ lastTestResult match {
73
+ case None =>
74
+ currentGroup.addOne(elem)
75
+ case Some (lastTest) if currentTest == lastTest =>
76
+ currentGroup.addOne(elem)
77
+ case Some (_) =>
78
+ groups.addOne(currentGroup.result())
79
+ currentGroup = newGroupBuilder().addOne(elem)
80
+ }
81
+
82
+ lastTestResult = Some (currentTest)
83
+ }
84
+
85
+ groups.addOne(currentGroup.result()).result()
86
+ }
87
+
44
88
}
0 commit comments