科特林。从集合中获取不同的值

Kotlin. Get distinct values from collection

数据看起来像这样

    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)
    )

我想获得“A”和“B”作为名称的唯一值。

如果集合看起来像这样就很容易了:

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

以下应按预期工作:

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
)

但是,我建议您尽可能替换嵌套列表,这样您就可以在映射时避免 when 块。如果可能的话,我会建议 Triple class 如下:

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)
}

如果您 want/need 保留嵌套列表,另一种可能性如下(感谢@gidds 的提示):

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)
}

另一种选择是创建自定义 class 来代表您的内部列表。

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)