I need to find first element in a list which fits predicate. But I need to check with it position in predicate.
list.findXXX { index, item ->
index > 19 && item.active
}
Is there such a function?
There is no such function yet, but you can easily write one yourself. It is not a lot of effort at all.
public inline fun <T> Iterable<T>.findIndexed(predicate: (Int, T) -> Boolean): T? {
forEachIndexed { i, e -> if (predicate(i, e)) return e }
return null
}
Alternatively, in general you can use a filterIndexed to first filter out the indexes that you want to exclude:
list
// .asSequence() // if you want to be lazy
.filterIndexed { i, _ -> i > 19 }
.find { item -> item.active }
In fact, you could just put the entire condition in filterIndexed and use firstOrNull afterwards. It just may not read as nicely as find.
Of course in this specific case you can also just drop the first 20.
I'm not familiar with such function, but I think this would work well for your example
list.drop(20).first{item -> item.isActive}
You can make your custom extension function to achieve what you want
fun <T> List<T>.firstCustomOrNull(
predicate: (index: Int, element: T) -> Boolean
): T? {
forEachIndexed { index, element ->
if (predicate(index, element)) return element
}
return null
}
now you can use that function the same way as .firstOrNull and you have access to the element and the index so you can use it in any custom way that you want:
list.firstCustomOrNull { index, element ->
element.active && index > 19
}
This solution will work for any case and you can customize it more, but if you want to keep it simple you can just drop the first 20 element.
Related
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
}
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)
How can I use distinctBy on a list of custom objects to strip out the duplicates? I want to determine "uniqueness" by multiple properties of the object, but not all of them.
I was hoping something like this would work, but no luck:
val uniqueObjects = myObjectList.distinctBy { it.myField, it.myOtherField }
Edit: I'm curious how to use distinctBy with any number of properties, not just two like in my example above.
You can create a pair:
myObjectList.distinctBy { Pair(it.myField, it.myOtherField) }
The distinctBy will use equality of Pair to determine uniqueness.
If you look at the implementation of the distinctBy, it just adds the value you pass in the lambda to a Set. And if the Set did not already contain the specified element, it adds the respective item of the original List to the new List and that new List is being returned as the result of distinctBy.
public inline fun <T, K> Iterable<T>.distinctBy(selector: (T) -> K): List<T> {
val set = HashSet<K>()
val list = ArrayList<T>()
for (e in this) {
val key = selector(e)
if (set.add(key))
list.add(e)
}
return list
}
So you can pass a composite object that holds the properties that you require to find the uniqueness.
data class Selector(val property1: String, val property2: String, ...)
And pass that Selector object inside the lambda:
myObjectList.distinctBy { Selector(it.property1, it.property2, ...) }
You can create a triple:
myObjectList.distinctBy { Triple(it.firstField, it.secondField, it.thirdField) }
The distinctBy will use equality of Triple to determine uniqueness.
*I have implemented in this way, it provides most Unique list 👍
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.
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.