Home > Blockchain >  Kotlin. Get distinct values from collection
Kotlin. Get distinct values from collection

Time:12-01

Data looks like this

    class Person (
        var id:Int, 
        var name:String
    )
    class Option (
        var level:Int
    )
    val p1 = Person(1, "A")
    val p2 = Person(2, "B")
    val opt1 = Option((0..1000).random())
    val opt2 = Option((0..1000).random())
    val opt3 = Option((0..1000).random())
    val opt4 = Option((0..1000).random())
    
    val arr = listOf(
        listOf(p1,p2,opt1), 
        listOf(p1,p2,opt2), 
        listOf(p1,p2,opt3), 
        listOf(p2,p1,opt4)
    )

I would like to get "A" and "B" as unique values of name.

It's easy if collection looks like this:

val simple = listOf(p1,p2,p2,p1).distinctBy{it.name}
simple.forEach {
    println(it.name)
}

CodePudding user response:

The following should work as expected:

fun main() {
    val p1 = Person(1, "A")
    val p2 = Person(2, "B")
    val opt1 = Option((0..1000).random())
    val opt2 = Option((0..1000).random())
    val opt3 = Option((0..1000).random())
    val opt4 = Option((0..1000).random())

    val arr = listOf(
        listOf(p1,p2,opt1),
        listOf(p1,p2,opt2),
        listOf(p1,p2,opt3),
        listOf(p2,p1,opt4)
    )

    val distinctNames = arr.flatten().mapNotNull {
        when(it) {
            is Person -> it.name
            else -> null
        }
    }.distinct()

    println(distinctNames)
}

class Person (
    var id:Int,
    var name:String
)

class Option (
    var level:Int
)

However, I would advise you to replace the nested Lists if possible so that you can avoid the when block while mapping. If possible I would suggest Triple class instead as follows:

fun main() {
    val p1 = Person(1, "A")
    val p2 = Person(2, "B")
    val opt1 = Option((0..1000).random())
    val opt2 = Option((0..1000).random())
    val opt3 = Option((0..1000).random())
    val opt4 = Option((0..1000).random())

    val arr = listOf(
        Triple(p1,p2,opt1),
        Triple(p1,p2,opt2),
        Triple(p1,p2,opt3),
        Triple(p2,p1,opt4)
    )

    val distinctNames = arr.flatMap { listOf(it.first.name, it.second.name) }
         .distinct()
    println(distinctNames)
}

Another possibility if you want/need to keep the nested Lists would be the following (thanks @gidds for the hint):

fun main() {
    val p1 = Person(1, "A")
    val p2 = Person(2, "B")
    val opt1 = Option((0..1000).random())
    val opt2 = Option((0..1000).random())
    val opt3 = Option((0..1000).random())
    val opt4 = Option((0..1000).random())

    val arr = listOf(
        listOf(p1,p2,opt1),
        listOf(p1,p2,opt2),
        listOf(p1,p2,opt3),
        listOf(p2,p1,opt4)
    )

    val distinctNames = arr.flatten().mapNotNull { (it as? Person)?.name }
        .distinct()

    println(distinctNames)
}

CodePudding user response:

Another option can be to create a custom class to represent your inner lists.

class PersonOption(
    val person1: Person,
    val person2: Person,
    val option: Option
)

val arr = listOf(
    PersonOption(p1, p2, opt1),
    PersonOption(p1, p2, opt2),
    PersonOption(p1, p2, opt3),
    PersonOption(p2, p1, opt4)
)

val names = arr.flatMap { listOf(it.person1.name, it.person2.name) }.distinct()
println(names)
  • Related