Functional listener with state - scala

Let's say in my pure Scala program i have a dependency to a Java service.
This Java service accepts a listener to notify me when some data changes.
Let's say the data is a tuple(x, y) and the java service calls the listener whenever X or Y changes but i'm interested only when X.
For this my listener has to save the last value of X, and forward the update/call only when oldX != X, so in order to have this my impure scala listener implementation has to hold a var oldX
val listener = new JavaServiceListener() {
var oldX;
def updated(val x, val y): Unit = {
if (oldX != x) {
oldX = x
//do stuff
}
}
javaService.register(listener)
How would i go about to design a wrapper for this kind of thing in Scala without val or mutable collections ? I can't at the JavaServiceListener level since i'm bound by the method signature, so I need another layer above which the java listener forwards to somehow

My preference would be to wrap it in a Monix Observable, then you can use distinctUntilChanged to eliminate consecutive duplicates. Something like:
import monix.reactive._
val observable = Observable.create(OverflowStrategy.Fail(10)){(sync) =>
val listener = new JavaServiceListener() {
def updated(val x, val y): Unit = {
sync.onNext(x)
}
}
javaService.register(listener)
Cancelable{() => javaService.unregister(listener)}
}
val distinctObservable = observable.distinctUntilChanged
Reactive programming allows you to use a pure model while the library handles all the difficult stuff.

First of all, if you are designing a purely functional program you cannot return Unit (neither Future[Unit], because Future does not suppress side effects).
If performance is not an issue I would make use of Kleisli[Option, xType, IO[Unit]] where T = Option. So the first thing you have to do is define (add the appropriate types)
def updated(oldX, x): Kleisli[Option, xType, xType] = Kleisli liftF {
if(x != oldX) None
else Some(x)
}
def doStuff(x, y): Kleisli[Option, xType, IO[Unit]] = Kleisli pure {
IO{
//doStuff
}
}
and now you can compose them in a for-comprehension something like that:
val result: Kleisli[Option, xType, IO[Unit]] = for{
xx <- updated(oldX, x)
effect <- doStuff(xx, y)
} yield effect
You can perform stateful compuation with ReaderWriterStateT, so you keep oldX as a state.

I found the solution I like with Cats and Cats-Effect:
trait MyListener {
def onChange(n: Int): Unit
}
class MyDistinctFunctionalListener(private val last: Ref[IO, Int], consumer: Int => Unit) extends MyListener {
override def onChange(newValue: Int): Unit = {
val program =
last
.getAndSet(newValue)
.flatMap(oldValue => notify(newValue, oldValue))
program.unsafeRunSync()
}
private def notify(newValue: Int, oldValue: Int): IO[Unit] = {
if (oldValue != newValue) IO(consumer(newValue)) else IO.delay(println("found duplicate"))
}
}
object MyDistinctFunctionalListener {
def create(consumer: Int => Unit): IO[MyDistinctFunctionalListener] =
Ref[IO].of(0).map(v => new MyDistinctFunctionalListener(v, consumer))
}
val printer: Int => Unit = println(_)
val functionalDistinctPrinterIO = MyDistinctFunctionalListener.create(printer)
functionalDistinctPrinterIO.map(fl =>
List(1, 1, 2, 2, 3, 3, 3, 4, 5, 5).foreach(fl.onChange)
).unsafeRunSync()
More stuff about handling shared state here https://github.com/systemfw/scala-italy-2018
it is debatable if this is worth it over the private var solution

Related

Wrap higher order function into progress bar

I have an iteration module which can apply an arbitrary function (Build generic reusable iteration module from higher order function) and would love to wrap it into a progressbar.
val things = Range(1,10)
def iterationModule[A](
iterationItems: Seq[A],
functionToApply: A => Any
): Unit = {
iterationItems.foreach(functionToApply)
}
def foo(s:Int) = println(s)
iterationModule[Int](things, foo)
A basic progressbar could look like:
import me.tongfei.progressbar.ProgressBar
val pb = new ProgressBar("Test", things.size)
things.foreach(t=> {
println(t)
pb.step
})
But how can the function which is passed to the iterator module be intercepted and surrounded with a progressbar, i.e. call the pb.step?
An annoying possibility would be to pass the mutable pb object into each function (have it implement an interface).
But is it also possible to intercept and surround the function being passed by this stepping logic?
However, when looping with Seq().par.foreach, this might be problematic.
I need the code to work in Scala 2.11.
edit
A more complex example:
val things = Range(1,100).map(_.toString)
def iterationModule[A](
iterationItems: Seq[A],
functionToApply: A => Any,
parallel: Boolean = false
): Unit = {
val pb = new ProgressBar(functionToApply.toString(), iterationItems.size)
if (parallel) {
iterationItems.par.foreach(functionToApply)
} else {
iterationItems.foreach(functionToApply)
}
}
def doStuff(inputDay: String, inputConfigSomething: String): Unit = println(inputDay + "__"+ inputConfigSomething)
iterationModule[String](things, doStuff(_, "foo"))
The function should be able to take the iteration item and additional parameters.
edit 2
import me.tongfei.progressbar.ProgressBar
val things = Range(1,100).map(_.toString)
def doStuff(inputDay: String, inputConfigSomething: String): Unit = println(inputDay + "__"+ inputConfigSomething)
def iterationModulePb[A](items: Seq[A], f: A => Any, parallel: Boolean = false): Unit = {
val pb = new ProgressBar(f.toString, items.size)
val it = if (parallel) {
items.par.iterator
} else {
items.iterator
}
it.foreach { x =>
f(x)
pb.step()
}
}
iterationModulePb[String](things, doStuff(_, "foo"))
After a little discussion I figured out how to use a Seq with standard iterators.
For Scala 2.13 this would be the most general form.
import me.tongfei.progressbar.ProgressBar
def iterationModule[A](items: IterableOnce[A], f: A => Any): Unit = {
val (it, pb) =
if (items.knowSize != -1)
items.iterator -> new ProgressBar("Test", items.knowSize)
else {
val (iter1, iter2) = items.iterator.split
iter1 -> new ProgressBar("Test", iter2.size)
}
it.foreach { x =>
f(x)
pb.step()
}
}
Note: most of the changes are just to make the code more generic, but the general idea is just to create a function that wraps both the original function and the call to the ProgressBar.
Edit
A simplified solution for 2.11
def iterationModule[A](items: Seq[A], parallel: Boolean = false)
(f: A => Any): Unit = {
val pb = new ProgressBar("test", items.size)
val it = if (parallel) {
items.iterator.par
} else {
items.iterator
}
it.foreach { a =>
f(a)
pb.step()
}
}

Abstract a synchronous function with its Future counterpart

I wrote a very simple mechanism that only allows a max number of function calls during a given number of seconds. See it as a basic rate limiter.
It takes the execution to limit as an argument and returns the return value of that original execution.
The problem is that executions can be synchronous (of type => A) or asynchronous (of type => Future[A]) and that leads to two extremely similar functions:
case class Limiter[A](max: Int, seconds: Int) {
private val queue = Queue[Long]()
def limit(value: => A): Option[A] = {
val now = System.currentTimeMillis()
if (queue.length == max) {
val oldest = queue.head
if (now - oldest < seconds * 1000) return None
else queue.dequeue()
}
queue.enqueue(now)
Some(value)
}
def limitFuture(future: => Future[A]): Future[Option[A]] = {
val now = System.currentTimeMillis()
if (queue.length == max) {
val oldest = queue.head
if (now - oldest < seconds * 1000) return Future(None)
else queue.dequeue()
}
future.map { x =>
queue.enqueue(now)
Some(x)
}
}
}
(I am not actually using Option but a set of types I defined, just using Option for simplicity sake)
Examples of execution:
// Prevent more than 5 runs/minute. Useful for example to prevent email spamming
val limit = Limit[Boolean](5, 60)
val result = limitFuture { sendEmail(...) } // `sendEmail` returns a future
// Prevent more than 1 run/hour. Useful for example to cache HTML response
val limit = Limit[String](1, 3600)
val limit { getHTML(...) } // `getHTML` returns the HTML as a string directly
How can I refactor these methods to avoid repetition? Later needs might include other argument types and not only direct type + Futured type, so I'd like to keep my options open if it's possible.
The only "solution" I could come up with so far is to replace limit:
def limit(value: => A): Option[A] = {
Await.result(limitFuture(Future.successful(value)), 5.seconds)
}
Well, it works, but it feels backwards. I would rather have the => A being the base version that other methods extend or, even better, a generic (private) method that both limit and limitFuture could extend.
Actually, it would be even better-er if a single limit function could take care of this regardless of argument but I doubt it's possible.
You can condense this down to one method with an implicit parameter handling the differences:
trait Limitable[A, B] {
type Out
def none: Out
def some(b: B, f: () => Unit): Out
}
implicit def rawLimitable[A]: Limitable[A, A] = new Limitable[A, A] {
type Out = Option[A]
def none = None
def some(a: A, f: () => Unit): Out = {
f()
Some(a)
}
}
implicit def futureLimitable[A]: Limitable[A, Future[A]] = new Limitable[A, Future[A]] {
type Out = Future[Option[A]]
def none = Future(None)
def some(future: Future[A], f: () => Unit): Out = future.map { a =>
f()
Some(a)
}
}
case class Limiter[A](max: Int, seconds: Int) {
private val queue = Queue[Long]()
def limit[B](in: => B)(implicit l: Limitable[A, B]): l.Out = {
val now = System.currentTimeMillis()
if (queue.length == max) {
val oldest = queue.head
if (now - oldest < seconds * 1000) return l.none
else queue.dequeue()
}
l.some(in, {() => queue.enqueue(now)})
}
}
And use it like:
val limit = Limit[String](1, 3600)
limit.limit("foo")
limit.limit(Future("bar"))
You can use Applicative typeclass from cats or scalaz. Applicative, among other things, lets you lift a value into some context F (using pure) and is also a functor, so you can use map on F[A].
Currently you want it for Id and Future types (you need ExecutionContext in scope for Future applicative to work). It will work for things like Vector or Validated, tho you might have problems adding custom collection types.
import cats._, implicits._
import scala.concurrent._
import scala.collection.mutable.Queue
case class Limiter[A](max: Int, seconds: Int) {
private val queue = Queue[Long]()
def limitA[F[_]: Applicative](value: => F[A]): F[Option[A]] = {
val now = System.currentTimeMillis()
if (queue.length == max) {
val oldest = queue.head
if (now - oldest < seconds * 1000) return none[A].pure[F]
else queue.dequeue()
}
value.map { x =>
queue.enqueue(now)
x.some
}
}
// or leave these e.g. for source compatibility
def limit(value: => A): Option[A] = limitA[Id](value)
def limitFuture(future: => Future[A])(implicit ec: ExecutionContext): Future[Option[A]] = limitA(future)
}
Notes:
I'm using none[A] instead of None: Option[A] and a.some instead of Some(a): Option[A]. These helpers are available in both cats and scalaz and you need them because F[_] here is not defined as covariant.
You have to specify Id as a type explicitly, e.g. .limitA[Id](3). This is not the case with Future, however.
You map call is strange. It is parsed as:
future.map {
queue.enqueue(now) // in current thread
x => Some(x)
}
Which is the same as
queue.enqueue(now) // in current thread
future.map {
x => Some(x)
}

Generating adaptors for higher-kinded interfaces

I often find myself in a scenario where I have defined an interface like so:
trait FooInterface [T[_]] {
def barA (): T[Int]
def barB (): T[Int]
def barC (): T[Int]
}
I then write a few different implementations each typed on the Higher Kinded Type that makes the most sense for that particular implementation:
object FooImpl1 extends FooInterface[Option] { ... }
object FooImpl2 extends FooInterface[Future] { ... }
object FooImpl3 extends FooInterface[({type X[Y] = ReaderT[Future, Database, Y]})#X] { ... }
All implementations are perfectly valid, all return their results wrapped in a particular Higher Kinded Type.
I then often come to writing some business logic, let's say that in the block of logic I am working with is using Future as a context, I might write something like this:
val foo: FooInterface[Future] = ???
def fn (): Future[Int] = Future { 42 }
val result: Future[Int] = for {
x <- foo.barA ()
y <- foo.barB ()
z <- foo.barC ()
w <- fn ()
} yield x + y + z + w
The above code would work really well with FooImpl2 however the other implementations do not slot in directly. In this scenario I always wind up writing simple adapters:
object FooImpl1Adapter extends FooInterface[Future] {
val t = new Exception ("Foo impl 1 failed.")
def barA (): Future[Int] = FooImpl1.barA () match {
case Some (num) => Future.successful (num)
case None => Future.failed (t)
}
def barB (): Future[Int] = FooImpl1.barB () match {
case Some (num) => Future.successful (num)
case None => Future.failed (t)
}
def barC (): Future[Int] = FooImpl1.barC () match {
case Some (num) => Future.successful (num)
case None => Future.failed (t)
}
}
case class FooImpl3Adapter (db: Database) extends FooInterface[Future] {
def barA (): Future[Int] = FooImpl3.barA ().run (db)
def barB (): Future[Int] = FooImpl3.barB ().run (db)
def barC (): Future[Int] = FooImpl3.barC ().run (db)
}
Writing adapters is fine but it involves a lot of boilerplate, especially for interfaces with lots of functions; what's more is that each method gets the exactly same adaptation treatment for each method. What I really want to do is lift an adaptor implementation from an existing implementation, only specify in adaption mechanism once.
I guess I want to be able to write something like this:
def generateAdapterFn[X[_], Y[_]] (implx: FooInterface[X])(f: X[?] => Y[?]): FooInterface[Y] = ???
So I could use it like so:
val fooImpl1Adapter: FooInterface[Future] = generateAdapterFn [?, Future] () { z => z match {
case Some (obj) => Future.successful (obj)
case None => Future.failed (t)
}}
The question is: How could I write the generateAdapterFn function?
I'm not really sure how to approach solving this, or if there are other common patterns or solutions to my problem. I suspect that to write the generateAdapterFn function I desire I would need to write a macro? If so how might that be done?
What you are looking for is a natural transformation from X to Y (what you called X[?] => Y[?]). In Cats is called a FunctionK (with the popular type alias ~>).
You could define a natural transformation between Option and Future as :
import cats.arrow.FunctionK
import scala.concurrent.Future
val option2future = new FunctionK[Option, Future] {
def apply[A](opt: Option[A]): Future[A] = opt match {
case Some(obj) => Future.succesful(obj)
case None => Future.failed(new Exception("none")) // t ??
}
}
With the kind projector compiler plugin this could be written more concise as :
val opt2fut = λ[FunctionK[Option, Future]]{
case Some(obj) => Future.succesful(obj)
case None => Future.failed(new Exception("none")) // t ??
}
Your generateAdapter function could then look like :
import cats.~>
def generateAdapter[X[_], Y[_]](implx: FooInterface[X])(f: X ~> Y): FooInterface[Y] =
new FooInterface[Y] {
def barA: Y[Int] = f(implx.barA)
def barB: Y[Int] = f(implx.barB)
def barC: Y[Int] = f(implx.barC)
}
You should then be able to create a FooInterface[Future]] as :
val fooFuture = generateAdapter(FooImpl1)(opt2fut)
Unrelated, you might be interested to read something about the free monad, which is used to solve similar problems as the one you are facing now.
Keep the code polymorphic for as long as possible. Instead of
val result: Future[Int] = for {
x <- foo.barA ()
y <- foo.barB ()
z <- foo.barC ()
w <- fn ()
} yield x + y + z + w
write
import scalaz.Monad
import scalaz.syntax.monad._
// or
import cats.Monad
import cats.syntax.all._
def result[M[_]: Monad](foo: FooInterface[M], fn: () => M[Int]): M[Int] = for {
x <- foo.barA ()
y <- foo.barB ()
z <- foo.barC ()
w <- fn ()
} yield x + y + z + w
This way, you avoid writing adapters for FooInterface altogether and only transform the final value (via a natural transformation (see Peter Neyens' answer) or also quite easily directly).
Expanding on Peter Neyen's answer (which I've marked as correct as it answers the important part of my question), here's a proof of concept for how generate the adapter at runtime using reflection:
def generateAdapterR[X[_], Y[_]](implx: FooInterface[X])(implicit
f: X ~> Y): FooInterface[Y] = {
import java.lang.reflect.{InvocationHandler, Method, Proxy}
object ProxyInvocationHandler extends InvocationHandler {
def invoke (
proxy: scala.AnyRef,
method: Method,
args: Array[AnyRef]): AnyRef = {
val fn = implx.getClass.getMethod (
method.getName,
method.getParameterTypes: _*)
val x = fn.invoke (implx, args: _*)
val fx = f.getClass.getMethods ()(0)
fx.invoke (f, x)
}
}
Proxy.newProxyInstance(
classOf[FooInterface[Y]].getClassLoader,
Array(classOf[FooInterface[Y]]),
ProxyInvocationHandler
).asInstanceOf[FooInterface[Y]]
}
Ideally it would be possible to type this function on T[_] as well, T being the type of the interface, so the function could be use to generate adaptors for any higher kinded interfaces at runtime.
Something like:
def genericGenerateAdapterR[T[_], X[_], Y[_]](implx: T[X[_]])(implicit
f: X ~> Y): T[Y[_]] = ???
Not really sure if that would be how to write it though...
I think the ideal solution would be to have a compiler plugin that generates the code in Peter Neyen's solution, avoiding reflection and avoiding boilerplate.

Scala case class: avoid recomputation of the property

I am asking this because I have encountered this use case many times.
Let's say we have a case class like this:
case class C(xs: Iterable[Int]) {
val max = xs.max
def ++(that: C) = C(xs ++ that.xs)
}
This works fine, but the ++ operation is inefficient, since the collection is needlessly traversed once more to compute the maximum of the result; since we already know the maximums of both collections, we could reuse that - by using something like this:
def ++(that: C) =
C(xs ++ that.xs, max = math.max(max, that.max))
This is just a simple example to demonstrate the purpose - the computation avoided could be a lot more complex, or maybe even a TCP data fetch.
How to avoid this recomputation (see the second code snippet), keeping the code elegant?
Something like this would work
class C private (val xs: Iterable[Int], val max: Int) {
def ++(that: C) = new C(xs ++ that.xs, math.max(this.max, that.max)
}
object C {
def apply(xs: Iterable[Int]) = new C(xs, xs.max)
}
Note that C is no longer a case class to avoid max and xs becoming inconsistent. If C was a case class, you could call e.g. c.copy(max = -1) and get an inconsistent instance.
case class C(xs: Iterable[Int]) {
private var maxOp = Option.empty[Int]
lazy val max = maxOp getOrElse {
maxOp = Some(xs.max)
maxOp.get
}
def ++(that: C) = {
val res = C(xs ++ that.xs)
res.maxOp = Some(math.max(this.max, that.max))
res
}
}
Since max is already a val (in contrast to a method) you could do it this way:
case class C private (xs: Iterable[Int], max: Int) {
def ++(that: C) = C(xs ++ that.xs, math.max(max, that.max))
def copy(_xs: Iterable[Int] = this.xs) = {
if (_xs == this.xs) {
C(xs, max)
} else {
C(_xs)
}
}
}
object C {
def apply(xs: Iterable[Int]): C = C(xs, xs.max)
}
If you are going to pattern match on this case class, then it depends on your use cases, if you can (or must) pattern match on max as well.
Update 1 As pointed out by Rüdiger I have added private to the constructor so that xs and max are consistent.
Update 2 As pointed out by som-snytt, the copy method must be handled as well to to prevent inconsistency.
sealed trait C {
val xs: Iterable[Int]
val max: Int
def ++(that: C) = ComposedC(this, that)
}
case class ValidatedC(xs: Iterable[Int]) extends C {
val max = xs.max
}
case class ComposedC(a: C, b: C) extends C {
val max = math.max(a.max, b.max)
val xs = a.xs ++ b.xs
}
object C {
def apply(xs: Iterable[Int]) = ValidatedC(xs)
}
A simpler solution (which doesn't enforce correctness) -
Introduce a way to provide pre-computed max and an auxiliary constructor that gets 2 Cs.
case class C(xs: Iterable[Int])(val max: Int = xs.max) {
def this(a: C, b: C) = {
this(a.xs ++ b.xs)(math.max(a.max, b.max))
}
def ++(that: C) = new C(this, that)
}

How can I extend Scala collections with an argmax method?

I would like to add to all collections where it makes sense, an argMax method.
How to do it? Use implicits?
On Scala 2.8, this works:
val list = List(1, 2, 3)
def f(x: Int) = -x
val argMax = list max (Ordering by f)
As pointed by mkneissl, this does not return the set of maximum points. Here's an alternate implementation that does, and tries to reduce the number of calls to f. If calls to f don't matter that much, see mkneissl's answer. Also, note that his answer is curried, which provides superior type inference.
def argMax[A, B: Ordering](input: Iterable[A], f: A => B) = {
val fList = input map f
val maxFList = fList.max
input.view zip fList filter (_._2 == maxFList) map (_._1) toSet
}
scala> argMax(-2 to 2, (x: Int) => x * x)
res15: scala.collection.immutable.Set[Int] = Set(-2, 2)
The argmax function (as I understand it from Wikipedia)
def argMax[A,B](c: Traversable[A])(f: A=>B)(implicit o: Ordering[B]): Traversable[A] = {
val max = (c map f).max(o)
c filter { f(_) == max }
}
If you really want, you can pimp it onto the collections
implicit def enhanceWithArgMax[A](c: Traversable[A]) = new {
def argMax[B](f: A=>B)(implicit o: Ordering[B]): Traversable[A] = ArgMax.argMax(c)(f)(o)
}
and use it like this
val l = -2 to 2
assert (argMax(l)(x => x*x) == List(-2,2))
assert (l.argMax(x => x*x) == List(-2,2))
(Scala 2.8)
Yes, the usual way would be to use the 'pimp my library' pattern to decorate your collection. For example (N.B. just as illustration, not meant to be a correct or working example):
trait PimpedList[A] {
val l: List[A]
//example argMax, not meant to be correct
def argMax[T <% Ordered[T]](f:T => T) = {error("your definition here")}
}
implicit def toPimpedList[A](xs: List[A]) = new PimpedList[A] {
val l = xs
}
scala> def f(i:Int):Int = 10
f: (i: Int) Int
scala> val l = List(1,2,3)
l: List[Int] = List(1, 2, 3)
scala> l.argMax(f)
java.lang.RuntimeException: your definition here
at scala.Predef$.error(Predef.scala:60)
at PimpedList$class.argMax(:12)
//etc etc...
Nice and easy ? :
val l = List(1,0,10,2)
l.zipWithIndex.maxBy(x => x._1)._2
You can add functions to an existing API in Scala by using the Pimp my Library pattern. You do this by defining an implicit conversion function. For example, I have a class Vector3 to represent 3D vectors:
class Vector3 (val x: Float, val y: Float, val z: Float)
Suppose I want to be able to scale a vector by writing something like: 2.5f * v. I can't directly add a * method to class Float ofcourse, but I can supply an implicit conversion function like this:
implicit def scaleVector3WithFloat(f: Float) = new {
def *(v: Vector3) = new Vector3(f * v.x, f * v.y, f * v.z)
}
Note that this returns an object of a structural type (the new { ... } construct) that contains the * method.
I haven't tested it, but I guess you could do something like this:
implicit def argMaxImplicit[A](t: Traversable[A]) = new {
def argMax() = ...
}
Here's a way of doing so with the implicit builder pattern. It has the advantage over the previous solutions that it works with any Traversable, and returns a similar Traversable. Sadly, it's pretty imperative. If anyone wants to, it could probably be turned into a fairly ugly fold instead.
object RichTraversable {
implicit def traversable2RichTraversable[A](t: Traversable[A]) = new RichTraversable[A](t)
}
class RichTraversable[A](t: Traversable[A]) {
def argMax[That, C](g: A => C)(implicit bf : scala.collection.generic.CanBuildFrom[Traversable[A], A, That], ord:Ordering[C]): That = {
var minimum:C = null.asInstanceOf[C]
val repr = t.repr
val builder = bf(repr)
for(a<-t){
val test: C = g(a)
if(test == minimum || minimum == null){
builder += a
minimum = test
}else if (ord.gt(test, minimum)){
builder.clear
builder += a
minimum = test
}
}
builder.result
}
}
Set(-2, -1, 0, 1, 2).argmax(x=>x*x) == Set(-2, 2)
List(-2, -1, 0, 1, 2).argmax(x=>x*x) == List(-2, 2)
Here's a variant loosely based on #Daniel's accepted answer that also works for Sets.
def argMax[A, B: Ordering](input: GenIterable[A], f: A => B) : GenSet[A] = argMaxZip(input, f) map (_._1) toSet
def argMaxZip[A, B: Ordering](input: GenIterable[A], f: A => B): GenIterable[(A, B)] = {
if (input.isEmpty) Nil
else {
val fPairs = input map (x => (x, f(x)))
val maxF = fPairs.map(_._2).max
fPairs filter (_._2 == maxF)
}
}
One could also do a variant that produces (B, Iterable[A]), of course.
Based on other answers, you can pretty easily combine the strengths of each (minimal calls to f(), etc.). Here we have an implicit conversion for all Iterables (so they can just call .argmax() transparently), and a stand-alone method if for some reason that is preferred. ScalaTest tests to boot.
class Argmax[A](col: Iterable[A]) {
def argmax[B](f: A => B)(implicit ord: Ordering[B]): Iterable[A] = {
val mapped = col map f
val max = mapped max ord
(mapped zip col) filter (_._1 == max) map (_._2)
}
}
object MathOps {
implicit def addArgmax[A](col: Iterable[A]) = new Argmax(col)
def argmax[A, B](col: Iterable[A])(f: A => B)(implicit ord: Ordering[B]) = {
new Argmax(col) argmax f
}
}
class MathUtilsTests extends FunSuite {
import MathOps._
test("Can argmax with unique") {
assert((-10 to 0).argmax(_ * -1).toSet === Set(-10))
// or alternate calling syntax
assert(argmax(-10 to 0)(_ * -1).toSet === Set(-10))
}
test("Can argmax with multiple") {
assert((-10 to 10).argmax(math.pow(_, 2)).toSet === Set(-10, 10))
}
}