How can I find the first element's method result that is not null? - kotlin

So I have parsers and want to use the first that does return a non-null value. How would I do that most elegantly?
return parsers.map { it.parse(content) }.firstOrNull { it != null }
would map all (million?) parsers before picking the first.
return parsers.firstOrNull { it.parse(content) != null }?.parse(content)
would run the (expensive?) parse() once again.
I know I can
for (parser in parsers) {
val result = parser.parse(content)
if (result != null) {
return result
}
}
return null
parsers.forEach { it.parse(content)?.run { return this } }
return null
is the shortest I can get but it's not nice to read.
I'm pretty sure there is a shortcut here that I don't see.

Use a sequence. It makes your computation lazy, so that you will only compute parse as many times as you need.
return parsers.asSequence()
.map { it.parse(content) }
.find { it != null }

As an alternative to the overhead of a Sequence, or mapping lots of values unnecessarily, you could use an extension method such as:
inline fun <T, R> List<T>.firstMappedNotNull(transform: (T) -> R): R? {
for (e in this)
return transform(e) ?: continue
return null
}
This uses the minimum of mapping function calls and temporary objects.  It's necessarily written in an imperative way, but it's quite short, and makes your own code short, clear, and functional.
(This version returns null if the list was empty or every mapping returned null.  You could of course change the signature and last line to throw an exception instead.)
It's a shame this function isn't already in the standard library.  But it's easy to add your own!

Also, you can use the following code:
parsers.asSequence()
.mapNotNull { it.parse(content) }
.first()

Related

Kotlin, remove duplicates from Linkedlist : smart cast is impossible

I implemented a LinkedList in kotlin and wrote a method to remove duplicates from it:
class Node (value:Int) {
var value = value
var next:Node? = null
fun addNodeToTail(value:Int){
var node = this
while (node.next != null) {
node = node.next
}
val newNode= Node(value)
node.next= newNode
}
fun removeDuplicates (){
val set = HashSet<Int>()
var node = this
set.add(node.value)
while(node.next != null){
if (set.contains(node.next?.value)){
node.next= node.next?.next
}else{
set.add(node.next.value)
node= node.next
}
}
}
}
In the last two lines:
set.add(node.next.value)
node= node.next
(and in the addNodeToTail method), the compiler says that smart cast is impossible because of complex expression. I have to add non-null asserted call (!!).
I want to understand why this solution is not accepted, although the while expression checks that node.next is not null. And I want to know if there is a better solution than using non-null asserted call (!!).
Thank you for your help
Pawel technically answered in the comment.
Basically smart casts are not always possible. In particular, if you define a mutable var of nullable type that is technically accessible by multiple threads, the compiler cannot guarantee that the value stays the same between the null check and the usage. That's why you get this error "smart cast impossible".
A common way of dealing with the problem is to store the value in a local val variable, to guarantee that this value will not change, and allow the compiler to smart cast it.
In your case though, it's not ideal because the while has to check the actual node's value every time. So you'll have to assert that the value is not null at some point, either with !! or with an elvis (?:) and an error() or throw.
I would personally go for:
while (node.next != null) {
val nextNode = node.next ?: throw ConcurrentModificationException()
if (set.contains(nextNode.value)) {
node.next = nextNode.next
} else {
set.add(nextNode.value)
node = nextNode
}
}

Is it considered bad convention when in iterating through two maps, I don't check if key exists in one of them?

I have two maps, let's call them oneMap and twoMap.
I am iterating through all the keys in oneMap, and if the key exists in twoMap I do something
like
fun exampleFunc(oneMap: Map<String, Any>, twoMap: Map<String, Any>) {
for((oneMapKey, oneMapVal) in oneMap) {
if (twoMap.containsKey(oneMapKey)) {
val twoMapVal = twoMap[oneMapKey]
if (twoMapVal == oneMapVal) {
//do more stuff
}
//do more stuff, I have more if statements
}
}
}
To avoid having more nested if statements, I was wondering if instead I could get rid of the
if (twoMap.containsKey(oneMapKey)) check. if twoMap doesn't contain the oneMapKey, we get a null object, and my code still works fine. I was wondering if this is considered bad convention though
fun exampleFunc(oneMap: Map<String, Any>, twoMap: Map<String, Any>) {
for((oneMapKey, oneMapVal) in oneMap) {
val twoMapVal = twoMap[oneMapKey]
if (twoMapVal == oneMapVal) {
//do more stuff
}
//do more stuff, I have more if statements
}
}
It depends. Do you wanna execute the "more stuff" or not?
If you do not wanna execute it you should keep the if condition. Though, if you are concerned about indentation (and deep if hierarchies) you can consider breaking out of the loop:
for((oneMapKey, oneMapVal) in oneMap) {
if (!twoMap.contains(oneMapKey)) continue // continue with next iteration
// do more stuff
}
If your map does not contain null values you can also get the value and check if the result was null (which means the key was not present in the map):
for((oneMapKey, oneMapVal) in oneMap) {
val twoMapVal: Any = twoMap[oneMapKey] ?: continue // continue with next iteration
// do more stuff
}
So its always good practice the remove useless code and (in my opinion) to have less if-hierarchies, as you can easily loose focus when you have lots of nested conditions.
As Tenfour04 says, omitting the containsKey() check is only an option if the map values aren't nullable; if they are, then []/get() gives no way to distinguish between a missing mapping and a mapping to a null value.
But if not (or if you want to ignore null values anyway), then I'd certainly consider omitting the check; the resulting code would be slightly shorter and slightly more efficient, without losing clarity or maintainability.  It could also avoid a potential race condition.  (Though in a multi-threaded situation, I'd be considering more robust protection!)
One variation is to use let() along with the safe-call ?. operator to restrict it to non-null cases:
for ((oneMapKey, oneMapVal) in oneMap) {
twoMap[oneMapKey]?.let { twoMapVal ->
if (twoMapVal == oneMapVal) {
// Do more stuff
}
// Do more stuff
}
}
Using ?.let() this way seems to be a fairly common idiom in Kotlin, so it should be fairly transparent.

Simplify testing of a null variable in an IF statement

In Kotlin I have this (which will not compile):
var list: MutableList<String>? = null
if (list.isNotEmpty()) {
}
This will compile:
var list: MutableList<String>? = null
if (list!!.isNotEmpty()) {
}
However, if list is null, a runtime exception will occur. I could do this:
var list: MutableList<String>? = null
if ((list != null) && list.isNotEmpty()) {
}
But this seems to be repetitive everywhere you need to test if something is null. Is there a more eloquent way of doing this in Kotlin?
In the specific case of checking if the list is not null or empty you can use:
if (!list.isNullOrEmpty())
For a list, it's better to avoid handling null state instead handle only empty and non-empty state. refer http://thefinestartist.com/effective-java/43.
Saying that, we don't need to explicitly check for null check and only empty check alone should do the trick.
var list : MutableList<String> = mutableListOf()
list.add("Test1")
list.takeIf { it.isNotEmpty() }?.forEach { println(it) }
We can use
takeIf
to check whether the list is empty or not.
The first way add this line
list = list?:MutableList<String>()
Second way
val isEmpty = list.isEmpty()?:false
if(isEmpty){}else{}
Third way
if (!list.isNullOrEmpty())
as #AndroidDev suggested
Why are getting an error? Since !! require non-null. if the object is null then it will throw NPE
I think most can be done with the safe operator ?. itself. So if you just want to iterate over the list (or reduce, map, or whatever), you can just simply do so directly:
val sumExpression = list?.joinToString("+") { it.someValue } ?: throw exception? use default value?
list?.forEach { println("an entry in the list: $it") } // if there are entries, just iterate over them... if not, there is nothing to do
list?.also {
consume(it) // consume now is only called if the list is not null
}
Enhancing it then with a condition is also rather easy with takeIf or takeUnless (depending on what you require):
list?.takeIf { it.isNotEmpty() }
Now you still have a nullable list and can again call any of the desired functions as shown before:
list?.takeIf( it.isNotEmpty() }?.also {
consume(it)
}
Also a variant instead of list.isNullOrEmpty() (already shown by gpuntos answer) is to compare the possible null value to the expected outcome, e.g.:
if(list?.isNotEmpty() == true) {
// do something with the non-empty list
}
In case it is null the condition simplifies to basically null == true which is false. However I wouldn't overuse that too much as then you don't see the actual nullable types so easily anymore. Such a usage may make sense, if what you are trying to calculate isn't already supported in its own extension function (as is with isNullOrEmpty()), e.g. for entering the if only if the count is 4 it makes sense to use something like: if (list?.count() == 4)...

How to asynchronously map over sequence

I want to iterate over a sequence of objects and return the first non-null of an async call.
The point is to perform some kind of async operation that might fail, and I have a series of fallbacks that I want to try in order, one after the other (i.e. lazily / not in parallel).
I've tried to do something similar to what I'd do if it were a sync call:
// ccs: List<CurrencyConverter>
override suspend fun getExchangeRateAsync(from: String, to: String) =
ccs.asSequence()
.map { it.getExchangeRateAsync(from, to) }
.firstOrNull { it != null }
?: throw CurrencyConverterException()
IntelliJ complains:
Suspension functions can only be called within coroutine body
Edit: To clarify, this works as expected if mapping on a List, but I want to see how I'd do this on a sequence.
So I guess this is because the map lambda isn't suspended? But I'm not sure how to actually do that. I tried a bunch of different ways but none seemed to work. I couldn't find any examples.
If I re-write this in a more procedural style using a for loop with an async block, I can get it working:
override suspend fun getExchangeRateAsync(from: String, to: String) {
for (cc in ccs) {
var res: BigDecimal? = async {
cc.getExchangeRateAsync(from, to)
}.await()
if (res != null) {
return res
}
}
throw CurrencyConverterException()
}
You are getting an error, because Sequence is lazy by default and it's map isn't an inline function, so it's scope isn't defined
You can avoid using Sequence by creating a list of lazy coroutines
// ccs: List<CurrencyConverter>
suspend fun getExchangeRateAsync(from: String, to: String) =
ccs
.map { async(start = CoroutineStart.LAZY) { it.getExchangeRateAsync(from, to) } }
.firstOrNull { it.await() != null }
?.getCompleted() ?: throw Exception()
This doesn't give any errors and seems to be working. But I'm not sure it's an idiomatic way
I would suggest replacing Sequence with Flow. Flow api and behavior is pretty much same as for Sequence, but with suspending options.
https://kotlinlang.org/docs/reference/coroutines/flow.html
Code:
override suspend fun getExchangeRateAsync(from: String, to: String) =
ccs.asFlow()
.map { it.getExchangeRateAsync(from, to) }
.firstOrNull { it != null }
?: throw CurrencyConverterException()
FWIW, I found the suggestion in How to asynchronously map over sequence to be very intuitive. The code at https://github.com/Kotlin/kotlin-coroutines-examples/blob/master/examples/suspendingSequence/suspendingSequence.kt defines SuspendingIterator which allows next() to suspend, then builds SuspendingSequence on top of it. Unfortunately, you need to duplicate extension functions like flatMap(), filter(), etc. since SuspendingSequence can't be related to Sequence, but I did this and am much happier with the result than using a Channel.

Return from `buildSequence` in Kotlin

I'm using the buildSequence function in Kotlin. How do I end the iteration in the middle of the function? I'm looking for something similar to C#'s yield break statement.
My code looks something like the following. I'm stuck at the TODO.
fun foo(list:List<Number>): Sequence<Number> = buildSequence {
if (someCondition) {
// TODO: Bail out early with an empty sequence
// return doesn't seem to work....
}
list.forEach {
yield(someProcessing(it))
}
}
EDIT
Apparently, I misdiagnosed the source. The issue is not returning from the buildSequence function. The following works for me:
fun foo(list:List<Number>): Sequence<Number> = buildSequence {
return#buildSequence
list.forEach {
yield(someProcessing(it))
}
}
EDIT 2
The issue is that I put the return in a local helper function that validates data at multiple points in the buildSequence (Hence the helper function). Apparently I'm not able to return from buildSequence within the helper function. The error message was not terribly helpful...
Just use return#buildSequence, which is a labeled return from lambda, while an unlabeled return would mean 'return from the function foo'.
See also: Whats does “return#” mean?
Since Kotlin v 1.3.x preferred sequence syntax changed. (buildSequence is replaced by kotlin.sequences.sequence)
Updated "early return from generator" code snippet (includes try-catch and == null early return examples) for post 1.3.x Kotlin:
// gen# is just a subjective name i gave to the code block.
// could be `anything#` you want
// Use of named returns prevents "'return' is not allowed here" errors.
private fun getItems() = sequence<Item> gen# {
val cursor: Cursor?
try {
cursor = contentResolver.query(uri,*args)
} catch (e: SecurityException) {
Log.w(APP_NAME, "Permission is not granted.")
return#gen
}
if (cursor == null) {
Log.w(APP_NAME, "Query returned nothing.")
return#gen
}
// `.use` auto-closes Closeable. recommend.
// https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/use.html
cursor.use {
// iterate over cursor to step through the yielded records
while (cursor.moveToNext()) {
yield(Item.Factory.fromCursor(cursor))
}
}
}
(Thx for all the prior posts that helped me get on "named return" track.)