-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add groupMap family of methods to NonEmptyVector and NonEmptySeq #4826
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -342,6 +342,163 @@ final class NonEmptyVector[+A] private (val toVector: Vector[A]) | |
| final def groupByNem[B](f: A => B)(implicit B: Order[B]): NonEmptyMap[B, NonEmptyVector[A]] = | ||
| NonEmptyMap.fromMapUnsafe(groupBy(f)) | ||
|
|
||
| /** | ||
| * Groups elements inside this `NonEmptyVector` according to the `Order` | ||
| * of the keys produced by the given key function. | ||
| * And each element in a group is transformed into a value of type B | ||
| * using the mapping function. | ||
| * | ||
| * {{{ | ||
| * scala> import scala.collection.immutable.SortedMap | ||
| * scala> import cats.data.NonEmptyVector | ||
| * scala> import cats.syntax.all._ | ||
| * scala> val nev = NonEmptyVector.of(12, -2, 3, -5) | ||
| * scala> val expectedResult = SortedMap(false -> NonEmptyVector.of("-2", "-5"), true -> NonEmptyVector.of("12", "3")) | ||
| * scala> val result = nev.groupMap(_ >= 0)(_.toString) | ||
| * scala> result === expectedResult | ||
| * res0: Boolean = true | ||
| * }}} | ||
| */ | ||
| final def groupMap[K, B](key: A => K)(f: A => B)(implicit K: Order[K]): SortedMap[K, NonEmptyVector[B]] = { | ||
| implicit val ordering: Ordering[K] = K.toOrdering | ||
| var m = TreeMap.empty[K, mutable.Builder[B, Vector[B]]] | ||
|
|
||
| for { elem <- toVector } { | ||
| val k = key(elem) | ||
|
|
||
| m.get(k) match { | ||
| case None => m += ((k, Vector.newBuilder[B] += f(elem))) | ||
| case Some(builder) => builder += f(elem) | ||
| } | ||
| } | ||
|
|
||
| m.map { case (k, v) => | ||
| (k, NonEmptyVector.fromVectorUnsafe(v.result())) | ||
| }: TreeMap[K, NonEmptyVector[B]] | ||
| } | ||
|
Comment on lines
+362
to
+378
|
||
|
|
||
| /** | ||
| * Groups elements inside this `NonEmptyVector` according to the `Order` | ||
| * of the keys produced by the given key function. | ||
| * And each element in a group is transformed into a value of type B | ||
| * using the mapping function. | ||
| * | ||
| * {{{ | ||
| * scala> import cats.data.{NonEmptyMap, NonEmptyVector} | ||
| * scala> import cats.syntax.all._ | ||
| * scala> val nev = NonEmptyVector.of(12, -2, 3, -5) | ||
| * scala> val expectedResult = NonEmptyMap.of(false -> NonEmptyVector.of("-2", "-5"), true -> NonEmptyVector.of("12", "3")) | ||
| * scala> val result = nev.groupMapNem(_ >= 0)(_.toString) | ||
| * scala> result === expectedResult | ||
| * res0: Boolean = true | ||
| * }}} | ||
| */ | ||
| final def groupMapNem[K, B](key: A => K)(f: A => B)(implicit K: Order[K]): NonEmptyMap[K, NonEmptyVector[B]] = | ||
| NonEmptyMap.fromMapUnsafe(groupMap(key)(f)) | ||
|
|
||
| /** | ||
| * Groups elements inside this `NonEmptyVector` according to the `Order` | ||
| * of the keys produced by the given key function. | ||
| * Then each element in a group is transformed into a value of type B | ||
| * using the mapping function. | ||
| * And finally they are all reduced into a single value | ||
| * using their `Semigroup`. | ||
| * | ||
| * {{{ | ||
| * scala> import scala.collection.immutable.SortedMap | ||
| * scala> import cats.data.NonEmptyVector | ||
| * scala> import cats.syntax.all._ | ||
| * scala> val nev = NonEmptyVector.of("Hello", "World", "Goodbye", "World") | ||
| * scala> val expectedResult = SortedMap("goodbye" -> 1, "hello" -> 1, "world" -> 2) | ||
| * scala> val result = nev.groupMapReduce(_.trim.toLowerCase)(_ => 1) | ||
| * scala> result === expectedResult | ||
| * res0: Boolean = true | ||
| * }}} | ||
| */ | ||
| final def groupMapReduce[K, B](key: A => K)(f: A => B)(implicit K: Order[K], B: Semigroup[B]): SortedMap[K, B] = | ||
| groupMapReduceWith(key)(f)(B.combine) | ||
|
|
||
| /** | ||
| * Groups elements inside this `NonEmptyVector` according to the `Order` | ||
| * of the keys produced by the given key function. | ||
| * Then each element in a group is transformed into a value of type B | ||
| * using the mapping function. | ||
| * And finally they are all reduced into a single value | ||
| * using their `Semigroup`. | ||
| * | ||
| * {{{ | ||
| * scala> import cats.data.{NonEmptyMap, NonEmptyVector} | ||
| * scala> import cats.syntax.all._ | ||
| * scala> val nev = NonEmptyVector.of("Hello", "World", "Goodbye", "World") | ||
| * scala> val expectedResult = NonEmptyMap.of("goodbye" -> 1, "hello" -> 1, "world" -> 2) | ||
| * scala> val result = nev.groupMapReduceNem(_.trim.toLowerCase)(_ => 1) | ||
| * scala> result === expectedResult | ||
| * res0: Boolean = true | ||
| * }}} | ||
| */ | ||
| final def groupMapReduceNem[K, B](key: A => K)(f: A => B)(implicit K: Order[K], B: Semigroup[B]): NonEmptyMap[K, B] = | ||
| NonEmptyMap.fromMapUnsafe(groupMapReduce(key)(f)) | ||
|
|
||
| /** | ||
| * Groups elements inside this `NonEmptyVector` according to the `Order` | ||
| * of the keys produced by the given key function. | ||
| * Then each element in a group is transformed into a value of type B | ||
| * using the mapping function. | ||
| * And finally they are all reduced into a single value | ||
| * using the provided combine function. | ||
| * | ||
| * {{{ | ||
| * scala> import scala.collection.immutable.SortedMap | ||
| * scala> import cats.data.NonEmptyVector | ||
| * scala> import cats.syntax.all._ | ||
| * scala> val nev = NonEmptyVector.of("Hello", "World", "Goodbye", "World") | ||
| * scala> val expectedResult = SortedMap("goodbye" -> 1, "hello" -> 1, "world" -> 2) | ||
| * scala> val result = nev.groupMapReduceWith(_.trim.toLowerCase)(_ => 1)(_ + _) | ||
| * scala> result === expectedResult | ||
| * res0: Boolean = true | ||
| * }}} | ||
| */ | ||
| final def groupMapReduceWith[K, B](key: A => K)(f: A => B)(combine: (B, B) => B)(implicit | ||
| K: Order[K] | ||
| ): SortedMap[K, B] = { | ||
| implicit val ordering: Ordering[K] = K.toOrdering | ||
| var m = TreeMap.empty[K, B] | ||
|
|
||
| for { elem <- toVector } { | ||
| val k = key(elem) | ||
|
|
||
| m.get(k) match { | ||
| case Some(b) => m = m.updated(key = k, value = combine(b, f(elem))) | ||
| case None => m += (k -> f(elem)) | ||
| } | ||
| } | ||
|
|
||
| m | ||
| } | ||
|
|
||
| /** | ||
| * Groups elements inside this `NonEmptyVector` according to the `Order` | ||
| * of the keys produced by the given key function. | ||
| * Then each element in a group is transformed into a value of type B | ||
| * using the mapping function. | ||
| * And finally they are all reduced into a single value | ||
| * using the provided combine function. | ||
| * | ||
| * {{{ | ||
| * scala> import cats.data.{NonEmptyMap, NonEmptyVector} | ||
| * scala> import cats.syntax.all._ | ||
| * scala> val nev = NonEmptyVector.of("Hello", "World", "Goodbye", "World") | ||
| * scala> val expectedResult = NonEmptyMap.of("goodbye" -> 1, "hello" -> 1, "world" -> 2) | ||
| * scala> val result = nev.groupMapReduceWithNem(_.trim.toLowerCase)(_ => 1)(_ + _) | ||
| * scala> result === expectedResult | ||
| * res0: Boolean = true | ||
| * }}} | ||
| */ | ||
| final def groupMapReduceWithNem[K, B](key: A => K)(f: A => B)(combine: (B, B) => B)(implicit | ||
| K: Order[K] | ||
| ): NonEmptyMap[K, B] = | ||
| NonEmptyMap.fromMapUnsafe(groupMapReduceWith(key)(f)(combine)) | ||
|
|
||
| /** | ||
| * Partitions elements in fixed size `NonEmptyVector`s. | ||
| * | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new
groupMap*methods add non-trivial behavior but there are currently no unit/property tests covering them forNonEmptySeq(unlikeNonEmptyList, which has explicitgroupMap/groupMapReduce*tests). Please add tests inNonEmptySeqSuitecoveringgroupMap,groupMapNem,groupMapReduce,groupMapReduceNem,groupMapReduceWith, andgroupMapReduceWithNem(e.g., consistency withtoSeq.toList.groupBy+ map/reduce).