【问题标题】:Easy way to negate a predicate (e.g. (String) -> Boolean)) in Kotlin在 Kotlin 中否定谓词(例如 (String) -> Boolean))的简单方法
【发布时间】:2018-08-28 11:59:58
【问题描述】:

给定一个谓词(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(..)。

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

【问题讨论】:

标签: kotlin


【解决方案1】:

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

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, _) -&gt; predicate(key) }。

以下变体展示了如何实现 Predicates.not 或 Predicate.negate 之类的东西:

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

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)   

【讨论】:

  • 请注意,这不会像编写 filterKeys { it != "hello" } 那样高效,因为您正在创建两个内部对象实例,每个实例都包含一个 lambda,而不是仅仅内联所有内容
  • 嗯是的...也许我应该弃用operator 并改用其他方法...但是.. ...主要的“问题”是,我已经有一个谓词...所以问题在于是否调用filterKeys { ! matchingHello(it) } 或filterKeys(not(matchingHello)) 然后...我真的很喜欢filterKeys(!matchingHello) 的样子;-) 或者我会添加额外的扩展功能a la @ 987654342@... 听起来不太好,但与 filterNot 一致,听起来也不太好 ;-)
  • Kotlin Collections 有 filterNot(predicate)。这不是你要找的东西吗? /** * Returns a list containing all elements not matching the given [predicate]. */ public inline fun &lt;T&gt; Iterable&lt;T&gt;.filterNot(predicate: (T) -&gt; Boolean): List&lt;T&gt; { return filterNotTo(ArrayList&lt;T&gt;(), predicate) }
  • 为什么不inline operator fun?
猜你喜欢
  • 2020-03-13
  • 1970-01-01
  • 2014-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-10
相关资源
最近更新 更多