在对象集合中签入Kotlin所有属性均为null,但设置了一个属性

c8ib6hqw  于 2023-03-09  发布在  Kotlin
关注(0)|答案(5)|浏览(216)

如何在对象集合(例如:List)中检入Kotlin所有属性都为null,但有一个属性不为null,并且以perfomat方式设置。
下面是一个例子,但是如果数据类对象有很多属性,这就很难看了。

data class Person(val name: String?, val age: Int?, val address: String?)

val people = listOf(
    Person("Mary", 20, "Street 111"),
    Person(null, 22, null),
    Person(null, 21, "Street 123")
)

val filteredAgeOnly = people.filter{ it.address == null && it.name == null && it.age != null }

filteredAgeOnly应该只包含年龄= 22的第二项。
如果数据类具有更多属性,则每次都必须使用&& it.newProperty == null来接触和扩展过滤。

eufgjt7s

eufgjt7s1#

我建议添加一个helper方法--这是最简单、最有效的方法(但是,正如您所注意到的,每次添加新属性时都必须添加prop == null)。

data class Person(val name: String?, val age: Int?, val address: String?) {
    fun allPropertiesAreNullExceptAge(): Boolean {
        return name == null && address == null && age != null
    }
}

那么,只有一个地方需要作出这样的改变,而我认为这是一个较可取的方法。

    • 奖金:**

您可以使用反射来编写这样的方法,但是请记住使用这种方法时的潜在开销(以及某种过度设计):

import kotlin.reflect.full.declaredMemberProperties

data class Person(val name: String?, val age: Int?, val address: String?) {

    fun allPropertiesAreNullExceptAge(): Boolean {
        // verify age is not null:
        if (this.age == null) {
            return false
        }

        // get all properties except age and verify them:
        // please notice those are only declared member properties,
        // if you need to check extension properties as well do another check with `declaredMemberExtensionProperties` property
        val memberProps = this::class.declaredMemberProperties.filter { it.name != this::age.name }
        return memberProps.all {
            it.getter.call(this) == null
        }
    }
}

示例:

fun main() {
    val p = Person(null, null, null)
    val p2 = Person("abc", null, null)
    val p3 = Person("abc", 10, "def")
    val p4 = Person(null, 10, null)

    println(p.allPropertiesAreNullExceptAge())
    println(p2.allPropertiesAreNullExceptAge())
    println(p3.allPropertiesAreNullExceptAge())
    println(p4.allPropertiesAreNullExceptAge())
}

// prints:
// false
// false
// false
// true

您也可以在筛选中使用这样的方法:

val allPersons = listOf(p, p2, p3, p4)
val ageOnly = allPersons.filter { it.allPropertiesAreNullExceptAge() }
ldfqzlk8

ldfqzlk82#

如果我很好地理解了您的问题,您可以用途:

data class Person(val name: String?, val age: Int?, val address: String?){
    fun hasNonNullAttributes(): Boolean {
        return listOf(name, age, address).all { it != null }
        // -----------------------------^ add other attributes
    }
}
eqfvzcg8

eqfvzcg83#

在Kotlin中,具有相同属性的数据类的示例被认为是相同的,所以这就是您可以做的。
首先,通过提供默认值null使所有属性都是可选的,例如

data class Person(val name: String? = null, val age: Int? = null, val address: String? = null)

那你就可以

val filteredAgeOnly = people.filter{ it == Person(age = it.age) }

当你添加新属性时,确保它们是可选的,那么这一行可以保持不变。

vof42yt1

vof42yt14#

您可以创建一个Person的“过滤器示例”,如下所示:

val compareToPerson = Person(null, 0, null)

然后通过比较内置数据类复制方法创建的本地副本来过滤列表:

val result = people
  .filter { it.copy(age = compareToPerson.age) == compareToPerson }

要过滤的属性的值是无关紧要的,它必须是非空的。在本例中我使用0。

t1qtbnec

t1qtbnec5#

如果你想让它成为动态的,你可以使用反射来检查成员属性是否为空:

val filteredAgeOnly = people.filter { person ->
    person::class.memberProperties.filter { it != Person::age }.all { it.getter.call(person) == null } && person.age != null
}

相关问题