给出一个谓词(String) -> Boolean
,我想知道是否有一种简单的方法可以否定该谓词的结果。
只要使用列表,我就可以简单地从filter
切换到filterNot
,但是,如果我有话说... Map
并使用filterKeys
,该怎么办?
到目前为止,我使用的是:
val myPredicate : (String) -> Boolean = TODO()
val map : Map<String, String> = TODO()
map.filterKeys { !myPredicate(it) }
但是我不知道为什么Collection
有一个重载的过滤功能,而Map
没有。此外,我还想知道,为什么没有类似于Java的东西,即Predicate.negate()
以及自Java 11 Predicate.not(..)
以来的东西。
还是它存在,而我还没有找到?
答案 0 :(得分:2)
当时我的方法是具有两个函数,一个使用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) }
那样,只需调用filterKeysNot(givenPredicate)
即可使用给定谓词,类似于在集合上使用filterNot
可以实现的谓词。
针对当时的问题,我能够进行重构,以便可以对数据进行适当的分区,因此不再需要谓词否定。
如果仅在极少数情况下需要它,我宁愿坚持使用filterKeys { !predicate(it) }
或filterNot { (key, _) -> predicate(key) }
。
以下变体显示了如何实现Predicates.not
或Predicate.negate
之类的东西:
以下内容将允许使用!
运算符对谓词求反(如果应允许多个参数,则需要适当的重载):
operator fun <T> ((T) -> Boolean).not() = { e : T -> !this(e) }
下一个允许使用not( { /* a predicate */ } )
。但是,至少对于我来说,这不是很容易理解:
inline fun <T> not(crossinline predicate: (T) -> Boolean) = { e : T -> !predicate(e)}
用法:
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)