scala / scala-library-next

backwards-binary-compatible Scala standard library additions
Apache License 2.0
67 stars 17 forks source link

MapFactory.iterate #126

Open Lasering opened 1 year ago

Lasering commented 1 year ago

I'm constantly doing (or variations of):

list.map { a =>
  val value = //some code to compute the value, mostly likely using `a`
  a.name -> value
}.toMap

Which is annoying since I'm allocating an intermediate list when I would prefer to build the map directly.

A method like this could be added to MapFactory:

import scala.collection.MapFactory
extension [CC[_, _]](factory: MapFactory[CC])
  def iterate[A, K, V](iterable: IterableOnce[A])(f: A => (K, V)): CC[K, V] =
    val builder = factory.newBuilder[K, V]
    iterable.iterator.foreach(a => builder.addOne(f(a)))
    builder.result()

(Feel free to bike shed the names/implementation)

Currently IterableFactory has some very good utility methods to construct iterables such as fill, iterate, range, and tabulate. MapFactory on the other hand has nothing.

Lasering commented 1 year ago

These methods are more difficult to argue for their inclusion but they are still useful (names could be improved):

extension [CC[_, _]](factory: MapFactory[CC])
  def iterateKey[A, K](iterable: IterableOnce[A])(key: A => K): CC[K, A] =
    iterate(iterable)(e => (key(e), e))
  def iterateValue[A, V](iterable: IterableOnce[A])(value: A => V): CC[A, V] =
    iterate(iterable)(e => (e, value(e)))
OndrejSpanel commented 1 year ago

You can use view to avoid intermediate collection:

list.view.map { a =>
  val value = //some code to compute the value, mostly likely using `a`
  a.name -> value
}.toMap

Does this have some drawbacks for you?

Lasering commented 1 year ago

Does this have some drawbacks for you?

In terms of performance no, but in terms of readability and consistency with the IterableFactory yes. I find it easier to read:

Map.iterate { a =>
  val value = //some code to compute the value, mostly likely using `a`
  a.name -> value
}

Mainly because the intention of creating a map is in the beginning of the code, and the cognitive load of reading the code is smaller.

jozic commented 1 year ago

Those are indeed very handy. I've added those to my small homegrown lib.

https://github.com/jozic/scalax-collection#maptomap

https://github.com/jozic/scalax-collection#tomapwithkey

https://github.com/jozic/scalax-collection#tomapwithvalue

But if they appear in this lib, i will happily switch.