Skip to content

Commit 145ee2d

Browse files
authored
Merge pull request #23 from BalmungSan/add-iterator-group-methods
Add groupMapReduce method to IterableOnceOps
2 parents 1f9b308 + 8f9fd9c commit 145ee2d

File tree

3 files changed

+147
-0
lines changed

3 files changed

+147
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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 scala.collection
14+
package next
15+
16+
private[next] final class NextIterableOnceOpsExtensions[A, CC[_], C](
17+
private val col: IterableOnceOps[A, CC, C]
18+
) extends AnyVal {
19+
/**
20+
* Partitions this IterableOnce into a map according to a discriminator function `key`. All the values that
21+
* have the same discriminator are then transformed by the `value` function and then reduced into a
22+
* single value with the `reduce` function.
23+
*
24+
* {{{
25+
* def occurrences[A](as: IterableOnce[A]): Map[A, Int] =
26+
* as.iterator.groupMapReduce(identity)(_ => 1)(_ + _)
27+
* }}}
28+
*
29+
* @note This will force the evaluation of the Iterator.
30+
*/
31+
def groupMapReduce[K, B](key: A => K)(f: A => B)(reduce: (B, B) => B): immutable.Map[K, B] = {
32+
val m = mutable.Map.empty[K, B]
33+
col.foreach { elem =>
34+
m.updateWith(key = key(elem)) {
35+
case Some(b) => Some(reduce(b, f(elem)))
36+
case None => Some(f(elem))
37+
}
38+
}
39+
m.to(immutable.Map)
40+
}
41+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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 scala.collection
14+
15+
import scala.language.implicitConversions
16+
17+
package object next {
18+
implicit final def scalaNextSyntaxForIterableOnceOps[A, CC[_], C](
19+
col: IterableOnceOps[A, CC, C]
20+
): NextIterableOnceOpsExtensions[A, CC, C] =
21+
new NextIterableOnceOpsExtensions(col)
22+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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 scala.collection.next
14+
15+
import org.junit.Assert._
16+
import org.junit.Test
17+
import scala.collection.IterableOnceOps
18+
import scala.collection.generic.IsIterableOnce
19+
20+
final class TestIterableOnceExtensions {
21+
import TestIterableOnceExtensions.LowerCaseString
22+
23+
@Test
24+
def iteratorGroupMapReduce(): Unit = {
25+
def occurrences[A](coll: IterableOnce[A]): Map[A, Int] =
26+
coll.iterator.groupMapReduce(identity)(_ => 1)(_ + _)
27+
28+
val xs = Seq('a', 'b', 'b', 'c', 'a', 'a', 'a', 'b')
29+
val expected = Map('a' -> 4, 'b' -> 3, 'c' -> 1)
30+
assertEquals(expected, occurrences(xs))
31+
}
32+
33+
@Test
34+
def iterableOnceOpsGroupMapReduce(): Unit = {
35+
def occurrences[A, CC[_], C](coll: IterableOnceOps[A, CC, C]): Map[A, Int] =
36+
coll.groupMapReduce(identity)(_ => 1)(_ + _)
37+
38+
val xs = Seq('a', 'b', 'b', 'c', 'a', 'a', 'a', 'b')
39+
val expected = Map('a' -> 4, 'b' -> 3, 'c' -> 1)
40+
assertEquals(expected, occurrences(xs))
41+
}
42+
43+
@Test
44+
def anyLikeIterableOnceGroupMapReduce(): Unit = {
45+
def occurrences[Repr](coll: Repr)(implicit it: IsIterableOnce[Repr]): Map[it.A, Int] =
46+
it(coll).iterator.groupMapReduce(identity)(_ => 1)(_ + _)
47+
48+
val xs = "abbcaaab"
49+
val expected = Map('a' -> 4, 'b' -> 3, 'c' -> 1)
50+
assertEquals(expected, occurrences(xs))
51+
}
52+
53+
@Test
54+
def customIterableOnceOpsGroupMapReduce(): Unit = {
55+
def occurrences(coll: LowerCaseString): Map[Char, Int] =
56+
coll.groupMapReduce(identity)(_ => 1)(_ + _)
57+
58+
val xs = LowerCaseString("abBcAaAb")
59+
val expected = Map('a' -> 4, 'b' -> 3, 'c' -> 1)
60+
assertEquals(expected, occurrences(xs))
61+
}
62+
}
63+
64+
object TestIterableOnceExtensions {
65+
final case class LowerCaseString(source: String) extends IterableOnce[Char] with IterableOnceOps[Char, Iterable, String] {
66+
override def iterator: Iterator[Char] = source.iterator.map(_.toLower)
67+
68+
override def scanLeft[B](z: B)(op: (B, Char) => B): Iterable[B] = ???
69+
override def filter(p: Char => Boolean): String = ???
70+
override def filterNot(pred: Char => Boolean): String = ???
71+
override def take(n: Int): String = ???
72+
override def takeWhile(p: Char => Boolean): String = ???
73+
override def drop(n: Int): String = ???
74+
override def dropWhile(p: Char => Boolean): String = ???
75+
override def slice(from: Int, until: Int): String = ???
76+
override def map[B](f: Char => B): Iterable[B] = ???
77+
override def flatMap[B](f: Char => IterableOnce[B]): Iterable[B] = ???
78+
override def flatten[B](implicit asIterable: Char => IterableOnce[B]): Iterable[B] = ???
79+
override def collect[B](pf: PartialFunction[Char,B]): Iterable[B] = ???
80+
override def zipWithIndex: Iterable[(Char, Int)] = ???
81+
override def span(p: Char => Boolean): (String, String) = ???
82+
override def tapEach[U](f: Char => U): String = ???
83+
}
84+
}

0 commit comments

Comments
 (0)