Skip to content

Commit 3e59456

Browse files
committed
Import splitWith from strawman-contrib
Taken from: https://github.com/scala/collection-strawman/issues/241
1 parent 2837fdb commit 3e59456

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

src/main/scala/scala/collection/decorators/SeqDecorator.scala

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,48 @@ class SeqDecorator[C, S <: HasSeqOps[C]](coll: C)(implicit val seq: S) {
4141
def intersperse[B >: seq.A, That](start: B, sep: B, end: B)(implicit bf: BuildFrom[C, B, That]): That =
4242
bf.fromSpecificIterable(coll)(new View.IntersperseSurround(seq(coll), start, sep, end))
4343

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+
4488
}

src/test/scala/scala/collection/decorators/SeqDecoratorTest.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ class SeqDecoratorTest {
1616
assertEquals(List(0, 1, 2), List(1).intersperse(0, 5, 2))
1717
}
1818

19+
@Test def splitWith(): Unit = {
20+
assertEquals(List(List()), List().splitWith(_ => true))
21+
assertEquals(List(List()), List().splitWith(_ => false))
22+
assertEquals(List(List(1), List(2, 4, 6), List(7)), List(1, 2, 4, 6, 7).splitWith(i => i % 2 == 0))
23+
assertEquals(List(List('a', 'b'), List('C', 'D'), List('e', 'f')), List('a', 'b', 'C', 'D', 'e', 'f').splitWith(_.isUpper))
24+
}
25+
1926
// This test just checks that there is no compilation error
2027
@Test def genericDecorator(): Unit = {
2128
val vector = Vector(1, 2, 3)

0 commit comments

Comments
 (0)