I want to pass `transform` to `toSet`

I want to write the process of toSet as follows.

val transform: (T) -> R = TODO("some transform here")
val src: Collection<T> = TODO("some collection here")

val dst: Set<R> = src.toSet { transform(it) }

This has the following advantages over the current method of writing map { transform(it) }.toSet().

  • Less code is required.
  • Improved processing efficiency.

In particular, I feel that the improvement in processing efficiency is beneficial because it eliminates the need to declare MutableSet as a temporary variable and initialize it with forEach.

What do you think?

Sorry if the English is hard to read, thanks.

It is already present

src.mapTo(mutableSetOf(), ::transform)
7 Likes

The “problem” with this is that the created set is a mutable one afterwards. I was also looking for ways to “lock” a set that was initially created by such a mapping operation to make it immutable afterwards, without converting it to a new set via .toSet() afterwards.

You could achieve that by appending an as cast like in listOf("").mapTo(mutableSetOf()) { it } as Set<String>, but that simply does not look nice.

1 Like

A MutableSet is a Set in the interface sense, so you don’t need a function which does that.

So a cast is really all it takes, it’s usually nicer to write it by typing the variable instead of the explicit cast:

val something: Set<String> = listOf("").mapTo(mutableSetOf()) { it }
1 Like

Right. Still a bit clumsy syntax.

You could probably make an extension function for this which uses a sequence under the hood to avoid additional list allocations:

fun <T, R> Collection<T>.mapToSet(transform: (T) -> R): Set<R> = 
    this.asSequence().map(transform).toSet()

You can then use it like so:

val myList = listOf(1, 2, 2, 3)
val mySet = myList.mapToSet { it * 2 }

Kotlin playground link: Kotlin Playground: Edit, Run, Share Kotlin Code Online

3 Likes

The builder APIs are still experimental but they are intended to address these sort of use cases.

fun main() {
    val orig = listOf(1, 2, 3)
    val transformed = buildSet {
        orig.mapTo(this) { it * 2 }
   }
   println(transformed)
} 
3 Likes