在 Kotlin Map 中是否有一种方法可以过滤掉空的 Any?值?

23

我正在尝试想出一个函数,通过应用单个函数,允许将Map<String,Any?>对象视为Map<String,Any>,从而实现类型推断。

我对Kotlin中的转换函数还不太熟悉,已经尝试了各种在映射上使用filterfilterValuesfilterNot等方法:

val input = mapOf(Pair("first",null))
val filtered: Map<String,Any> = input.filter { it.value!=null }

它也无法编译任何一个。

input.filterValues { it!=null }
input.filterNot { it.value==null }
input.filterNot { it.value is Nothing }

我能做到的最接近的是应用多个步骤或者有一个未经检查的转换警告。我本以为过滤值为!=null就足够了。我唯一的想法是这可能与泛型有关?

3个回答

25

过滤函数返回与原始 map 相同的通用类型 Map。要转换值的类型,需要将值从 Any? 映射到 Any,执行强制类型转换。编译器无法知道你传递给 filter() 的谓词确保过滤后的 map 的所有值都不为空,因此它不能使用类型推断。所以最好使用

val filtered: Map<String, Any> = map.filterValues { it != null }.mapValues { it -> it.value as Any }

或者定义一个函数,在一个单独的传递中完成过滤和转换,从而能够使用智能转换:

fun filterNotNullValues(map: Map<String, Any?>): Map<String, Any> {
    val result = LinkedHashMap<String, Any>()
    for ((key, value) in map) {
        if (value != null) result[key] = value
    }
    return result
}

调用mapValues是否可以简化,或者我们只能接受Map.Entry作为输入吗?对我来说,它似乎很奇怪,它不直接提供值类型V并期望返回类型R,但我想这样做可能会带来性能损耗,因为遍历entry set并不是那么高效。也许函数名称太模糊了? - Harry J
我刚刚意识到 .mapValues { it.value as Any } 可以达到相同的结果,并且不需要传递已经可访问的 it - Harry J
1
我认为这与性能无关。无论映射函数接受条目还是值,都不会改变任何东西:mapValues()函数仍然需要遍历所有条目。接受条目而不仅仅是一个值允许做更多的事情,因为您可能需要访问键来决定如何转换值。 - JB Nizet
1
它比去除警告的效率要低,而在这种情况下去除警告是安全的。如果您真的要创建自己的函数,按照我的答案实现它比在地图上进行两次传递更有效。 - JB Nizet
好的,从性能角度来看这是有道理的。由于我还很新,所以Kotlin的流/迭代函数对我来说仍然有点困惑。 - Harry J
显示剩余2条评论

16
编译器并未对其进行足够深入的类型分析,以推断例如 input.filterValues { it != null } 从映射中过滤出 null 值,因此生成的映射应具有非空值类型。基本上,任何谓词都可能具有任意类型和可空性方面的含义。
在 stdlib 中没有专门用于过滤映射中的 null 值的特殊函数(就像可迭代对象中的.filterIsInstance<T>()一样)。因此,最简单的解决方法是应用无检查转换,从而告诉编译器您确定没有违反类型安全性:
@Suppress("UNCHECKED_CAST")
fun <K, V> Map<K, V?>.filterNotNullValues() = filterValues { it != null } as Map<K, V>

另请参见:有类似问题的另一个问题,它涉及到is检查。


1
我喜欢这个函数,它似乎应该与filterNotNull()一起用于列表/可迭代对象,但我不确定相比那些应用该函数会如何修改计算成本。 - Harry J

2
这不会产生任何警告 kotlin 1.5.30
listOfNotNull(
        nullableString?.let { "key1" to it },
        nullableString?.let { "key2" to it }
    ).toMap()

我要提醒一下,这样做会产生很多你不需要的新对象。@hotkey 提供的解决方案更好,而且效率更高。 - Jorn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接