36

I have a list as below {("a", 1), ("b", 2), ("c", 3), ("a", 4)}

I want to convert it to a map of list as below {("a" (1, 4)), ("b", (2)), ("c", (3)))}

i.e. for a, we have a list of 1 and 4, since the key is the same.

The answer in How to convert List to Map in Kotlin? only show unique value (instead of duplicate one like mine).

I tried associateBy in Kotlin

    data class Combine(val alpha: String, val num: Int)
    val list = arrayListOf(Combine("a", 1), Combine("b", 2), Combine("c", 3), Combine("a", 4))
    val mapOfList = list.associateBy ( {it.alpha}, {it.num} )
    println(mapOfList)

But doesn't seems to work. How could I do it in Kotlin?

4
  • each entry in the map would be String as the key and the list as the value?
    – Aaron He
    Commented Nov 1, 2017 at 0:39
  • Right... I can't find of a good function to do it, except for the conventional way of looping though using immutable collection. Looks not concise.
    – Elye
    Commented Nov 1, 2017 at 0:41
  • You need to do associateBy({it.alpha}, {it.num})
    – Vince
    Commented Nov 1, 2017 at 0:42
  • Not helping, the "a" will only contain 4. What I want is "a" with (1, 4).
    – Elye
    Commented Nov 1, 2017 at 0:45

3 Answers 3

31

Code

fun main(args: Array<String>) {
    data class Combine(val alpha: String, val num: Int)
    val list = arrayListOf(Combine("a", 1), Combine("b", 2), Combine("c", 3), Combine("a", 4))
    val mapOfList = list.associateBy ( {it.alpha}, {it.num} )
    println(mapOfList)
    val changed = list
        .groupBy ({ it.alpha }, {it.num})
    println(changed)
}

Output

{a=4, b=2, c=3}
{a=[1, 4], b=[2], c=[3]}

How it works

  • First it takes the list
  • It groups the Combines by their alpha value to their num values
3
  • 1
    Great! groupBy is indeed the answer. I improve the answer with val result = list.groupBy { it.alpha }.mapValues { it.value.map { it.num } } Thanks. Vote up for you and tick. (If you think my question helps others as well... do give a vote to it :)
    – Elye
    Commented Nov 1, 2017 at 2:09
  • 3
    Note that there's groupBy overload with two selectors: key and value, so you don't have to call mapValue in the end: groupBy({ it.apha }, { it.num })
    – Ilya
    Commented Nov 1, 2017 at 12:14
  • The collection API cheatsheet medium.com/mobile-app-development-publication/…
    – Elye
    Commented Sep 17, 2020 at 3:49
18

You may group the list by alpha first and then map the value to List<Int>:

data class Combine(val alpha: String, val num: Int)
val list = arrayListOf(Combine("a", 1), Combine("b", 2), Combine("c", 3), Combine("a", 4))
val mapOfList = list
        .groupBy { it.alpha }
        .mapValues { it.value.map { it.num } }
println(mapOfList)
2
  • Thanks mate. Your came in late a bit. Else I would give you a tick. Anyway, I upvote your answer!
    – Elye
    Commented Nov 1, 2017 at 2:10
  • If you think my question could help others, do upvote my question ya... Thanks :)
    – Elye
    Commented Nov 1, 2017 at 2:11
1

Here's a slightly more concise version of Jacky Choi's solution.

It combines the grouping and the transforming into one call to groupBy().

val mapOfList = list
        .groupBy (
            keySelector = { it.name },
            valueTransform = { it.num },
        )

Not the answer you're looking for? Browse other questions tagged or ask your own question.