Простой способ отрицать предикат (например, (String) -> Boolean)) в Kotlin - PullRequest
0 голосов
/ 28 августа 2018

Учитывая предикат (String) -> Boolean Я задавался вопросом, есть ли простой способ отрицать результат этого предиката. Пока я использую список, я могу просто переключаться с filter на filterNot, но что если у меня есть, скажем ... a 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(..).

Или он существует, а я его просто не нашел?

1 Ответ

0 голосов
/ 30 августа 2018

В то время мой подход состоял в том, чтобы иметь две функции, одна с использованием 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)   
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...