Home > Mobile >  Kotlin: How convert from Set to Map?
Kotlin: How convert from Set to Map?

Time:08-22

I have Set<FlagFilter> and I need to convert it to Map<Class<out FlagFilter>, FlagFilter>.

I tried doing it like this:

val result: Map<Class<out FlagFilter>, FlagFilter> =
     target
        .takeIf { !it.isEmpty() }
         ?.map { mapOf(it.javaClass to it) }
         ?: emptyMap<>()

but instead of a Map it turns out to be a List and I get a compilation error:

Type mismatch.
Required: Map<Class<out FlagFilter>, FlagFilter>
Found: List<Map<Class<FlagFilter>, FlagFilter>>

What am I doing wrong? As if there is not enough operation, but I do not understand yet which one

CodePudding user response:

map isn't anything to do with the Map type - it's a functional programming term (coming from a broader mathematical concept) that basically means a function that maps each input value to an output value.

So it's a transformation or conversion that takes a collection of items, transforms each one, and results in another collection with the same number of items. In Kotlin, you get a List of items (unless you're working with a Sequence, in which case you get another Sequence that yields the same number of items).

It's worth getting familiar with the kotlin.collections package - there's lots of useful stuff in there! But each function has a specific purpose, in terms of how they process the collection and what they return:

  • map - returns a new value for each item
  • onEach - returns the original items (allows you to do something with each, then continue processing the collection)
  • forEach - returns nothing (allows you to do something with each, but as a final operation - you can't chain another operation, it's terminal)
  • filter - returns a subset of the original items, matching a predicate
  • first - returns a single item, matching a predicate
  • reduce - returns a single item, transforming the values to produce a single result
  • count - returns a single item, based on an attribute of the collection (not the values themselves)

There's more but you get the idea - some things transform, some things pass-through, some things give you an identically sized collection, or a potentially smaller one, or a single value. map is just the one that takes a collection, and gives you a collection of the same size where every item has been (potentially) altered.

Like Vadik says, use one of the associate* functions to turn values into a Map object, effectively transforming each item in the collection into a Map.Entry. Which is technically mapping it to a mapping, so I wasn't totally accurate earlier when I said it's nothing to do with Maps, but I figured I'd save this thought til the end ;)

CodePudding user response:

Just use associateBy extension function:

val result: Map<Class<out FlagFilter>, FlagFilter> =
    target.associateBy { it.javaClass }

Or if you want to fix your code, remove the excessive call of mapOf(). Just convert your Set to List of Pairs, and then call toMap() to create a map:

val result: Map<Class<out FlagFilter>, FlagFilter> =
    target.map { it.javaClass to it }.toMap()
  • Related