@@ -41,4 +41,49 @@ 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 [That ](p : seq.A => Boolean )(implicit bf : BuildFrom [C , seq.A , That ]): That = {
60
+ def newGroupBuilder () = seq().iterableFactory.newBuilder[seq.A ]
61
+
62
+ // TODO: How to get a builder of a nested target collection?
63
+ val groups : mutable.Builder [seq.A , That ] = bf.newBuilder(coll)
64
+ val it : Iterator [seq.A ] = seq(coll).iterator
65
+
66
+ var currentGroup = newGroupBuilder()
67
+ var lastTestResult = Option .empty[Boolean ]
68
+
69
+ while (it.hasNext) {
70
+ val elem = it.next()
71
+ val currentTest = p(elem)
72
+
73
+ lastTestResult match {
74
+ case None =>
75
+ currentGroup.addOne(elem)
76
+ case Some (lastTest) if currentTest == lastTest =>
77
+ currentGroup.addOne(elem)
78
+ case Some (_) =>
79
+ groups.addOne(currentGroup.result())
80
+ currentGroup = newGroupBuilder().addOne(elem)
81
+ }
82
+
83
+ lastTestResult = Some (currentTest)
84
+ }
85
+
86
+ groups.addOne(currentGroup.result()).result()
87
+ }
88
+
44
89
}
0 commit comments