Easy way to negate a predicate (e.g. (String) -> Boolean)) in Kotlin - kotlin

Given a predicate (String) -> Boolean I wondered whether there is an easy way to negate the outcome of that predicate.
As long as I use a list, I can simply switch from filter to filterNot, but what if I have, lets say... a Map and use filterKeys?
What I used so far is:
val myPredicate : (String) -> Boolean = TODO()
val map : Map<String, String> = TODO()
map.filterKeys { !myPredicate(it) }
But I wonder why there is an overloaded filter-function for Collection, but not for Map. Moreover I also wonder, why there isn't something similar to what we have in Java, i.e. Predicate.negate() and since Java 11 Predicate.not(..).
Or does it exist and I just haven't found it?

My approach at that time was to have two functions, one using the not-operator and the other being a simple not-function accepting a predicate. Today I can't really recommend that approach anymore, but would rather choose the following instead, if I have to deal with many predicate negations for keys or values again:
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) }
That way a given predicate can simply be used by just calling filterKeysNot(givenPredicate) similar to what was already possible with filterNot on collections.
For the problem I had at that time I was able to do a refactoring so that the data could be partitioned appropriately and therefore the predicate negation wasn't needed anymore.
If I only need it in rare occasions I would rather stick to filterKeys { !predicate(it) } or filterNot { (key, _) -> predicate(key) }.
The following variants show how something like Predicates.not or Predicate.negate could be implemented:
The following will allow to use the !-operator to negate a predicate (if several parameters should be allowed an appropriate overload is required):
operator fun <T> ((T) -> Boolean).not() = { e : T -> !this(e) }
The next allows to use not( { /* a predicate */ } ). This however, at least for me, isn't really more readable:
inline fun <T> not(crossinline predicate: (T) -> Boolean) = { e : T -> !predicate(e)}
Usages:
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)

Related

Providing only one type parameter to an extension function with multiple type parameters in Kotlin

Introduction
In Kotlin I have a generic conversion extension function that simplifies conversion of this object of type C to an object of another type T (declared as the receiver) with additional conversion action that treats receiver as this and also provides access to original object:
inline fun <C, T, R> C.convertTo(receiver: T, action: T.(C) -> R) = receiver.apply {
action(this#convertTo)
}
It is used like this:
val source: Source = Source()
val result = source.convertTo(Result()) {
resultValue = it.sourceValue
// and so on...
}
I noticed I often use this function on receivers that are created by parameterless constructors and thought it would be nice to simplify it even more by creating additional version of convertTo() that automates construction of the receiver based on its type, like this:
inline fun <reified T, C, R> C.convertTo(action: T.(C) -> R) = with(T::class.constructors.first().call()) {
convertTo(this, action) // calling the first version of convertTo()
}
Unfortunately, I cannot call it like this:
source.convertTo<Result>() {}
because Kotlin expects three type parameters provided.
Question
Given above context, is it possible in Kotlin to create a generic function with multiple type parameters that accepts providing just one type parameter while other types are determined from the call-site?
Additional examples (by #broot)
Imagine there is no filterIsInstance() in stdlib and we would like to implement it (or we are the developer of stdlib). Assume we have access to #Exact as this is important for our example. It would be probably the best to declare it as:
inline fun <T, reified V : T> Iterable<#Exact T>.filterTyped(): List<V>
Now, it would be most convenient to use it like this:
val dogs = animals.filterTyped<Dog>() // compile error
Unfortunately, we have to use one of workarounds:
val dogs = animals.filterTyped<Animal, Dog>()
val dogs: List<Dog> = animals.filterTyped()
The last one isn't that bad.
Now, we would like to create a function that looks for items of a specific type and maps them:
inline fun <T, reified V : T, R> Iterable<T>.filterTypedAndMap(transform: (V) -> R): List<R>
Again, it would be nice to use it just like this:
animals.filterTypedAndMap<Dog> { it.barkingVolume } // compile error
Instead, we have this:
animals.filterTypedAndMap<Animal, Dog, Int> { it.barkingVolume }
animals.filterTypedAndMap { dog: Dog -> dog.barkingVolume }
This is still not that bad, but the example is intentionally relatively simple to make it easy to understand. In reality the function would be more complicated, would have more typed params, lambda would receive more arguments, etc. and then it would become hard to use. After receiving the error about type inference, the user would have to read the definition of the function thoroughly to understand, what is missing and where to provide explicit types.
As a side note: isn't it strange that Kotlin disallows code like this: cat is Dog, but allows this: cats.filterIsInstance<Dog>()? Our own filterTyped() would not allow this. So maybe (but just maybe), filterIsInstance() was designed like this exactly because of the problem described in this question (it uses * instead of additional T).
Another example, utilizing already existing reduce() function. We have function like this:
operator fun Animal.plus(other: Animal): Animal
(Don't ask, it doesn't make sense)
Now, reducing a list of dogs seems pretty straightforward:
dogs.reduce { acc, item -> acc + item } // compile error
Unfortunately, this is not possible, because compiler does not know how to properly infer S to Animal. We can't easily provide S only and even providing the return type does not help here:
val animal: Animal = dogs.reduce { acc, item -> acc + item } // compile error
We need to use some awkward workarounds:
dogs.reduce<Animal, Dog> { acc, item -> acc + item }
(dogs as List<Animal>).reduce { acc, item -> acc + item }
dogs.reduce { acc: Animal, item: Animal -> acc + item }
The type parameter R is not necessary:
inline fun <C, T> C.convertTo(receiver: T, action: T.(C) -> Unit) = receiver.apply {
action(this#convertTo)
}
inline fun <reified T, C> C.convertTo(action: T.(C) -> Unit) = with(T::class.constructors.first().call()) {
convertTo(this, action) // calling the first version of convertTo()
}
If you use Unit, even if the function passed in has a non-Unit return type, the compiler still allows you to pass that function.
And there are other ways to help the compiler infer the type parameters, not only by directly specifying them in <>. You can also annotate the variable's result type:
val result: Result = source.convertTo { ... }
You can also change the name of convertTo to something like convert to make it more readable.
Another option is:
inline fun <T: Any, C> C.convertTo(resultType: KClass<T>, action: T.(C) -> Unit) = with(resultType.constructors.first().call()) {
convertTo(this, action)
}
val result = source.convertTo(Result::class) { ... }
However, this will conflict with the first overload. So you have to resolve it somehow. You can rename the first overload, but I can't think of any good names off the top of my head. I would suggest that you specify the parameter name like this
source.convertTo(resultType = Result::class) { ... }
Side note: I'm not sure if the parameterless constructor is always the first in the constructors list. I suggest that you actually find the parameterless constructor.
This answer does not solve the stated problem but incorporates input from #Sweeper to provide a workaround at least simplifying result object instantiation.
First of all, the main stated problem can be somewhat mitigated if we explicitly state variable's result type (i.e. val result: Result = source.convertTo {}) but it's not enough to solve the problem in cases described by #broot.
Secondly, using KClass<T> as result parameter type provides ability to use KClass<T>.createInstance() making sure we find a parameterless constructor (if there's any – if there is none, then result-instantiating convertTo() is not eligible for use). We can also benefit from Kotlin's default parameter values to make result parameter type omittable from calls, we just need to take into account that action might be provided as lambda (last parameter of call) or function reference – this will require two versions of result-instantiating convertTo().
So, taking all the above into account, I've come up with this implementation(s) of convertTo():
// version A: basic, expects explicitly provided instance of `receiver`
inline fun <C, T> C.convertTo(receiver: T, action: T.(C) -> Unit) = receiver.apply {
action(this#convertTo)
}
// version B: can instantiate result of type `T`, supports calls where `action` is a last lambda
inline fun <C, reified T : Any> C.convertTo(resultType: KClass<T> = T::class, action: T.(C) -> Unit) = with(resultType.createInstance()) {
(this#convertTo).convertTo(this#with, action)
}
// version C: can instantiate result of type `T`, supports calls where `action` is passed by reference
inline fun <C, reified T : Any> C.convertTo(action: T.(C) -> Unit, resultType: KClass<T> = T::class) = with(resultType.createInstance()) {
(this#convertTo).convertTo(T::class, action)
}
All three versions work together depending on a specific use case. Below is a set of examples explaining what version is used in what case.
class Source { var sourceId = "" }
class Result { var resultId = "" }
val source = Source()
fun convertX(result: Result, source: Source) {
result.resultId = source.sourceId
}
fun convertY(result: Result, source: Source) = true
fun Source.toResultX(): Result = convertTo { resultId = it.sourceId }
fun Source.toResultY(): Result = convertTo(::convertX)
val result0 = source.convertTo(Result()) { resultId = it.sourceId } // uses version A of convertTo()
val result1: Result = source.convertTo { resultId = it.sourceId } // uses version B of convertTo()
val result2: Result = source.convertTo(::convertX) // uses version C of convertTo()
val result3: Result = source.convertTo(::convertY) // uses version C of convertTo()
val result4: Result = source.toResultX() // uses version B of convertTo()
val result5: Result = source.toResultY() // uses version C of convertTo()
P.S.: As #Sweeper notices, convertTo might not be a good name for the result-instantiating versions (as it's not as readable as with basic version) but that's a secondary problem.

Get index of given element from array extension function kotlin

I'd like to understand Kotlin extension functions more and am trying to implement an extension function for a List, to get the index of an element by passing the value of the position (if that makes sense).
What I have:
fun List<String>.getItemPositionByName(item: String): Int {
this.forEachIndexed { index, it ->
if (it == item)
return index
}
return 0
}
Although this works fine, I would need the same thing for Int too.
To my question, is there a way of combining this into one extension function instead of two seperate ones? I acknowledge that this isn't a lot of code and wouldn't hurt to be duplicated but out of interest and for future references.
I'm aware of this question Extension functions for generic classes in Kotlin where the response is - as I understand it at least - "doesn't quite work like this, but I don't really need it for type but "just" for String and Int.
Kotlin supports what C++ people would refer to as specialization to a certain degree. It works just fine for very basic types like you're using so what you're asking of is definitely possible.
We can declare the following declarations. Of course you could just duplicate the code and you'd be on your way.
public fun List<String>.getItemPositionByName(item: String) = ...
public fun List<Int>.getItemPositionByName(item: String) = ...
If you're not a fan of repeating the code, the idiomatic way would be to make use of file-private functions and simply delegating to the private function.
private fun <T> getItemImpl(list: List<T>, item: T): Int {
list.forEachIndexed { index, it ->
if (it == item)
return index
}
return -1
}
public fun List<String>.getItemPositionByName(item: String) = getItemImpl(this, item)
public fun List<Int>.getItemPositionByName(item: Int) = getItemImpl(this, item)
This limits the getItemImpl which is fully generic to the current file you're in while the Int and String specializations are publicly available anywhere else.
Attempting to call getItemPositionByName on any list which is not of type List<Int> or List<String> will fail with a type error.
Kotlin Playground Link: https://pl.kotl.in/NvIRXwmpU
And just in case you weren't aware, the method you're implementing already exists in the standard library (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/index-of.html)
The Kotlin standard library already has a function that does this: indexOf().
val one = listOf("a", "b", "c").indexOf("b")
check(one == 1)
One option is to look at the implementation of that function.
There is also the first() function, which you could use if you wanted write your own generic version:
fun <T> List<T>.getItemPositionByName(item: T) = withIndex()
.first { (_, value) -> item == value }
.index
fun main(args: Array<String>) {
val one = listOf("a", "b", "c").getItemPositionByName("b")
check(one == 1)
}
Or, rewriting your original version to use generics:
fun <T> List<T>.getItemPositionByName(item: T): Int {
this.forEachIndexed { index, it ->
if (it == item)
return index
}
return 0
}

Kotlin constructor reference with generics

I have this code in (Rx)Java:
Observable.fromArray(1, 2, 3)
.flatMap(this::intToBooleanObservable, Pair::new)
.....
I would expect to corresponding Kotlin code to look like:
Observable.fromArray(1, 2, 3)
.flatMap(::intToBooleanObservable, ::Pair)
.....
However the compiler cannot infer the generic type of Pair, so the best I can do right now is:
.flatMap(::intToBooleanObservable, { a, b -> a to b })
Which isn't as concise as I would like it to be.
Is there a way to achieve this without declaring the variables a and b?
Same trouble here. A few other workarounds (in the order I used them), you may like one of those.
1) Writing your own operator:
fun <T, U> Single<T>.flatMapPair(func: (T) -> Single<U>) : Single<Pair<T, U>> {
return this.flatMap { t -> func.invoke(t).map { u -> t to u } }
}
2) Move the wrapping to the conditional Observable (here intToBooleanObservable), returning the result as a Pair or a more explicit and custom type (sealed class with 2 childs, like Success and Failure). This enable more explicit code :
when(it) {
is Success -> ...
is Failure -> ...
}
3) Depending on intToBooleanObservable result you have now 2 different scenario (I imagine). Usually one is a sort of failure/denial, quick to resolve. For this matter write a filter with side effect where the predicate is an Observable, thus avoiding the problem :
fun <T> Observable<T>.filterSingle(predicate: (T) -> Single<Boolean>, rejectionFunction: (T) -> Unit): Observable<T> = ... //filter with the given predicate, and call rejectionFunction if item doesn't pass
4) The last method work only with boolean result. What if I am interested by the reason behind failure/refusal to give a meaningful message ? For the sake of homogeneous code, I dropped this operator. Inspired by other functionals languages, I defined a Either type and defined generic Either+RxJava operators; mapRight, flatMapRight and more important dropLeft. dropLeft is like a generalization of filterSingle.
inline fun <L, R> Observable<Either<L, R>>.dropLeft(crossinline sideEffect: (L) -> Unit): Observable<R> = this.lift { downObserver ->
object: Observer<Either<L, R>> {
override fun onError(throwable: Throwable?) = downObserver.onError(throwable)
override fun onSubscribe(disposable: Disposable?) = downObserver.onSubscribe(disposable)
override fun onComplete() = downObserver.onComplete()
override fun onNext(either: Either<L, R>) = when (either) {
is Right -> downObserver.onNext(either.value)
is Left -> sideEffect(either.value)
}
}
}
Hope it could help.

In Kotlin, how do I idiomatically access nullable nested map values, or return a default?

Quick Kotlin best practices question, as I couldn't really work out the best way to do this from the documentation.
Assume I have the following nested map (typing specified explicitly for the purpose of this question):
val userWidgetCount: Map<String, Map<String, Int>> = mapOf(
"rikbrown" to mapOf(
"widgetTypeA" to 1,
"widgetTypeB" to 2))
Can the following mode be any more succinct?
fun getUserWidgetCount(username: String, widgetType: String): Int {
return userWidgetCount[username]?.get(widgetType)?:0
}
In other words, I want to return the user widget count iff the user is known and they have an entry for that widget type, otherwise zero. In particular I saw I can use [] syntax to access the map initially, but I couldn't see a way to do this at the second level after using ?..
I would use an extension operator method for that.
// Option 1
operator fun <K, V> Map<K, V>?.get(key: K) = this?.get(key)
// Option 2
operator fun <K, K2, V> Map<K, Map<K2, V>>.get(key1: K, key2: K2): V? = get(key1)?.get(key2)
Option 1:
Define an extension that provides get operator for nullable map. In Kotlin's stdlib such approach appears with Any?.toString() extension method.
fun getUserWidgetCount(username: String, widgetType: String): Int {
return userWidgetCount[username][widgetType] ?: 0
}
Option 2:
Create a special extension for map of maps. In my opinion, it is better because it shows the contract of the map of maps better than two gets in a row.
fun getUserWidgetCount(username: String, widgetType: String): Int {
return userWidgetCount[username, widgetType] ?: 0
}

Efficient map and filter combination vs stdlibs

I'm trying to write an efficient solution to a common map/filter paradigm. In Kotlin, you can write code that looks like this:
schedule.daysOfWeek.map { it.adjustInto(today) as LocalDate }
.filterTo(datesOnSchedule) { it.isBefore(endDate) }
Generically, I'm applying a map, then filtering the mapped values based on a condition. However, an intermediate collection is created for this. This seems unnecessary. I wrote a little function that should do the same thing, but without the intermediate collection.
inline fun <T, R> Iterable<T>.mapThenFilter(predicate: (R) -> Boolean, transform: (T) -> R) {
mapThenFilter(ArrayList<R>(), predicate, transform)
}
inline fun <T, R, C : MutableCollection<in R>>
Iterable<T>.mapThenFilter(collection: C, predicate: (R) -> Boolean, transform: (T) -> R): C {
for (element in this) {
val mapped = transform(element)
if(predicate(mapped)) {
collection.add(mapped)
}
}
return collection
}
However, IntelliJ is suggesting a stdlib replacement for my function that would make it look like:
inline fun <T, R, C : MutableCollection<in R>>
Iterable<T>.mapThenFilter(collection: C, predicate: (R) -> Boolean, transform: (T) -> R): C {
this.map { transform(it) }
.filterTo(collection) { predicate(it) }
return collection
}
Which turns my optimization straight back into the original code I wrote and re-introduces the inefficiency of creating multiple collections. Is there some optimization going on here that I am not aware of?
No, there is no optimization; the IntelliJ IDEA suggestion is intended to show you the more idiomatic way to perform a certain operation and does not always preserve the performance of the original code. Obviously you know what you're doing, so you should either ignore the suggestion of the inspection or suppress it.