Skip to content

Commit 8bb19fb

Browse files
committed
#11 Add groupMap and groupMapReduce extensions
1 parent 83c9cef commit 8bb19fb

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

compat/src/main/scala-2.11_2.12/scala/collection/compat/PackageShared.scala

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ private[compat] trait PackageShared {
3030
*/
3131
type Factory[-A, +C] = CanBuildFrom[Nothing, A, C]
3232

33+
type IsTraversableLikeAux[A1, Repr] = IsTraversableLike[Repr] { type A = A1 }
34+
3335
implicit class FactoryOps[-A, +C](private val factory: Factory[A, C]) {
3436

3537
/**
@@ -154,6 +156,11 @@ private[compat] trait PackageShared {
154156
self: Traversable[A]): TraversableExtensionMethods[A] =
155157
new TraversableExtensionMethods[A](self)
156158

159+
implicit def toTraversableLikeExtensionMethods[Repr](self: Repr)(
160+
implicit traversable: IsTraversableLike[Repr])
161+
: TraversableLikeExtensionMethods[traversable.A, Repr] =
162+
new TraversableLikeExtensionMethods[traversable.A, Repr](traversable.conversion(self))
163+
157164
implicit def toTraversableOnceExtensionMethods[A](
158165
self: TraversableOnce[A]): TraversableOnceExtensionMethods[A] =
159166
new TraversableOnceExtensionMethods[A](self)
@@ -243,6 +250,40 @@ class TraversableExtensionMethods[A](private val self: c.Traversable[A]) extends
243250
def iterableFactory: GenericCompanion[Traversable] = self.companion
244251
}
245252

253+
class TraversableLikeExtensionMethods[A, Repr](private val self: c.GenTraversableLike[A, Repr])
254+
extends AnyVal {
255+
256+
def groupMap[K, B, VThat, That](key: A => K)(f: A => B)(
257+
implicit traversable: IsTraversableLikeAux[A, Repr],
258+
innerBf: CanBuildFrom[Repr, B, VThat],
259+
outerBf: CanBuildFrom[c.GenMap[K, Repr], (K, VThat), That]): That = {
260+
val grouped = self.groupBy(key)
261+
val outerB = outerBf(grouped)
262+
for ((k, repr) <- grouped.toIterator) {
263+
val innerB = innerBf(repr)
264+
for (a <- traversable.conversion(repr)) innerB += f(a)
265+
outerB.+=((k, innerB.result()))
266+
}
267+
outerB.result()
268+
}
269+
270+
def groupMapReduce[K, B, That](key: A => K)(f: A => B)(reduce: (B, B) => B)(
271+
implicit traversable: IsTraversableLikeAux[A, Repr],
272+
bf: CanBuildFrom[c.GenMap[K, Repr], (K, B), That]): That = {
273+
val grouped = self.groupBy(key)
274+
val b = bf(grouped)
275+
for ((k, repr) <- grouped.toIterator) {
276+
val elem = traversable
277+
.conversion(repr)
278+
.toIterator
279+
.map(f)
280+
.reduce(reduce)
281+
b.+=((k, elem))
282+
}
283+
b.result()
284+
}
285+
}
286+
246287
class MapViewExtensionMethods[K, V, C <: scala.collection.Map[K, V]](
247288
private val self: IterableView[(K, V), C])
248289
extends AnyVal {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Scala (https://www.scala-lang.org)
3+
*
4+
* Copyright EPFL and Lightbend, Inc.
5+
*
6+
* Licensed under Apache License 2.0
7+
* (http://www.apache.org/licenses/LICENSE-2.0).
8+
*
9+
* See the NOTICE file distributed with this work for
10+
* additional information regarding copyright ownership.
11+
*/
12+
13+
package test.scala.collection
14+
15+
import org.junit.Test
16+
import org.junit.Assert._
17+
18+
import scala.collection.compat._
19+
20+
class TraversableLikeTest {
21+
22+
@Test
23+
def groupMap(): Unit = {
24+
val res = Seq("foo", "test", "bar", "baz")
25+
.groupMap(_.length)(_.toUpperCase())
26+
assertEquals(Map(3 -> Seq("FOO", "BAR", "BAZ"), 4 -> Seq("TEST")), res)
27+
}
28+
29+
@Test
30+
def groupMapReduce(): Unit = {
31+
val res = Seq("foo", "test", "bar", "baz")
32+
.groupMapReduce(_.length)(_.toUpperCase())(_ + _)
33+
assertEquals(Map(3 -> "FOOBARBAZ", 4 -> "TEST"), res)
34+
}
35+
}

0 commit comments

Comments
 (0)