在 Kotlin 中否定谓词(例如 (String) -> Boolean))的简单方法

Rol*_*and 4 kotlin

给定一个谓词,(String) -> Boolean我想知道是否有一种简单的方法来否定该谓词的结果。只要我使用列表,我就可以简单地从 切换filterfilterNot,但是如果我有,比方说... aMap并使用怎么办filterKeys

到目前为止我使用的是:

val myPredicate : (String) -> Boolean = TODO()
val map : Map<String, String> = TODO()

map.filterKeys { !myPredicate(it) }
Run Code Online (Sandbox Code Playgroud)

但我想知道为什么有一个重载的过滤函数 for Collection,而不是 for Map。此外,我还想知道,为什么没有与 Java 中类似的东西,即Predicate.negate()从 Java 11 开始Predicate.not(..)

或者它确实存在而我只是没有找到它?

Rol*_*and 5

当时我的方法是有两个函数,一个使用not- 运算符,另一个是not接受谓词的简单 - 函数。今天,我真的不能再推荐这种方法,但如果我必须再次处理键或值的许多谓词否定,我宁愿选择以下方法:

inline fun <K, V> Map<out K, V>.filterKeysNot(predicate: (K) -> Boolean) = filterKeys { !predicate(it) }
inline fun <K, V> Map<out K, V>.filterValuesNot(predicate: (V) -> Boolean) = filterValues { !predicate(it) }
Run Code Online (Sandbox Code Playgroud)

这样,给定的谓词可以简单地通过调用filterKeysNot(givenPredicate)类似于filterNot集合上已经可以实现的方式来使用。

对于当时遇到的问题,我能够进行重构,以便可以对数据进行适当的分区,因此不再需要谓词否定。

如果我只在极少数情况下需要它,我宁愿坚持使用filterKeys { !predicate(it) }or filterNot { (key, _) -> predicate(key) }

以下变体显示了类似Predicates.notPredicate.negate可以如何实现:

以下将允许使用!- 运算符来否定谓词(如果应允许多个参数,则需要适当的重载):

operator fun <T> ((T) -> Boolean).not() = { e : T -> !this(e) }
Run Code Online (Sandbox Code Playgroud)

接下来允许使用not( { /* a predicate */ } )。然而,至少对我来说,这并不是真正更具可读性:

inline fun <T> not(crossinline predicate: (T) -> Boolean)  = { e : T -> !predicate(e)}
Run Code Online (Sandbox Code Playgroud)

用途:

val matchingHello : (String) -> Boolean = { it == "hello" }

mapOf("hello" to "world", "hi" to "everyone")
       .filterKeys(!matchingHello)
// or  .filterKeys(not(matchingHello))
// or  .filterKeys(matchingHello.not())
// or as shown above:
//     .filterKeysNot(matchingHello)
       .forEach(::println)   
Run Code Online (Sandbox Code Playgroud)