Switch observable on condition - kotlin

I have two observables and I want to use the first one unless it doesn't give me what I want (in this case an empty list). If that's the case I wwant to switch to the second one.
fun test() {
listSource1().switchMap {
if (it.isEmpty()) listSource2() else listSource1()
}
}
fun listSource1() = Observable.just(emptyList<String>())
fun listSource2() = Observable.just(listOf("hello"))
Is there a better way than this? it seems strange to map listSource1 to listSource1, is this the correct way to do it?

FlatMap the first to see if the item is an empty list:
Observable<List<T>> source = ...
Observable<List<T>> fallbackSource = ...
source.flatMap(list -> {
if (list.isEmpty()) {
return fallbackSource;
}
return Observable.just(list);
});

Related

How to only return a flow of list when certain condition is met?

I have an overriden function that returns a flow of list and if the condition is not met, I emit an emptyList() to cover up the corner case:
override fun returnFlow(): Flow<List<Item>> {
return combine(booleanFlow()) { items, boolean ->
if (!boolean) {
items
} else {
emptyList()
}
}
}
I want to remove the else {} logic and change it to only emitting a list when boolean is false. Ideally I would like something similar to this:
override fun returnFlow(): Flow<List<Item>> {
return combine(booleanFlow()) { items, boolean ->
while (!boolean) {
items
}
}
}
Can I use something like cancelFlow() or return Nothing?
I tried how to stop Kotlin flow when certain condition occurs and it doesn't work since the return type changes to Flow<Unit>.
Use combineTransform instead of combine. Instead of always emitting the item returned by the lambda, this lets you choose whether or not to emit an item by calling emit.
override fun returnFlow(): Flow<List<Item>> {
return combineTransform(booleanFlow()) { items, boolean ->
if (!boolean) {
emit(items)
}
}
}

Kotlin arrow transform a List of failures to a Failure of a list

How can I transform the following:
List<Try<String>>
to:
Try<List<String>>
Using kotlin and the functional library arrow (0.8.2). I would like to wrap it in a custom exception. It does not matter which one of the 'String' failed.
Update:
As the below answers will suffice, but I find it really hard to read. So, I implemented the following:
Create the following function:
fun getFailedStrings(result: List<Try<String>>): List<Failure> {
return result.fold(
initial = listOf(),
operation = { accumulator, nextUpdate ->
nextUpdate.fold(
ifSuccess = { accumulator },
ifFailure = { accumulator + Failure(it) }
)
})
}
Then use the result of the function:
return if (failedStrings.isNotEmpty()) {
failedStrings.first() // or whatever fits your usecase
} else {
// strings is the initial result of List<Try<String>>
Success(strings.mapNotNull { it.orNull() })
}
If we don't care about keeping the original exceptions we could do something like this with traverse:
val traversedTries = tries.traverse(Try.applicative(), ::identity)
This will return an instance of type Try<ListK<String>> with either all the strings or the first exception it finds.
ListK extends from List but we can optionally cast it by adding .map { it as List<String> } in the end if we need it to be Try<List<String>>
Alternatively, if we want to split the successes and failures we can create the following function:
fun <A> List<Try<A>>.splitSuccessFailure() : Tuple2<List<A>, List<Throwable>> =
fold(emptyList<A>() toT emptyList<Throwable>()) { (successes, failures), it ->
it.fold({ successes toT (failures + it) }, { (successes + it) toT failures })
}
Then, when we want to use it we can do the following:
val (successes, failures) = invalidTries.splitSuccessFailure()
Giving us two lists with the success values and failures respectively.
this seems to work:
fun convert(input: List<Try<String>>): Try<List<String>> =
input.fold(Try.just(emptyList())) { acc, i ->
acc.flatMap { list ->
i.flatMap {
Try.just(list + it)
}
}
}

brief function code for null check in kotlin

I have a test function and return Int.
fun test ():Int {
colors?.let { colorsArrayList ->
color1 = colorsArrayList.getOrNull(0)?.let {
return if (HexColorValidator().validate(it)) {
Color.parseColor(it)
} else {
Color.parseColor("#8DE7C1")
}
} ?: kotlin.run {
return Color.parseColor("#8DE7C1")
}
} ?: run {
return Color.parseColor("#8DE7C1")
}
return Color.parseColor("#8DE7C1")
}
}
can I write a brief then now?
return Color.parseColor("#8DE7C1")
this very repeated. can brief this line code?
Whenever I see code with a lot of conditional logic, I try to remember that I can "push" nulls rightward. Instead of handling if/else every time you need to test for null, imagine that you just take what you want (happy path) and pass the nulls on. Eventually, at the end, you'll end up with either the answer you want or null, and can return the value you want.
For example (mostly untested):
fun test() =
colors
?.getOrNull(0)
?.let { if(HexColorValidator().validate(it)) Color.parseColor(it) else null }
?: Color.parseColor("#8DE7C1")
Another way to make this easier to read is to extend String (what I'm presuming you have in colors) to hide the call to HexColorValidator:
fun String.parseColor(): Int? =
if (HexColorValidator().validate(this)) Color.parseColor(this)
else null
And then your test() function gets a bit simpler:
fun test(): Int =
colors
?.getOrNull(0)
?.parseColor()
?: Color.parseColor("#8DE7C1")

It it possible to break from foreachline

is it possible to break from foreachline. my code :
fun test() {
bufferedReader.forEachLine {
val nameParam = it.split(":")[0]
if (name == "test")
return // here i wan to return from function
}
}
I've tried 'return#foreachline' but it just continue to next line
No, it's not: non-local returns are only supported for inline functions, and forEachLine { ... } is not an inline one, so you can only use return#forEachLine that exits the lambda.
An alternative that allows it is to read the lines first and then iterate over them:
bufferedReader.lines().use { lines ->
for (it in lines) {
val nameParam = it.split(":")[0]
if (name == "test")
break
}
}
Here, .use { ... } ensures that the lazy Stream created by .lines() is closed once it is not needed anymore.
Break and continue for custom control structures are not implemented yet.
You could use println().
The following simple hack works perfectly fine:
val fileToScann = File("file.txt")
fileToScan.forEachLine {
if( it.contains("12345") ) {
throw Exception("line found:"+it)
}
}
throw Exception("line not found")
}

RxJava Return single, execute completable after

I'm trying to accomplish the following: Return some data as single, execute a completable after. The following code does not compile due to single.andThen(). The actions need to be executed in this order.
val single = Single.create<String> { it.onSuccess("result") }
val completable = Completable.create { println("executing cleanup") }
val together = single.andThen(completable)
together.subscribe(
{ println(it) },
{ println(it) }
)
Use flatMap:
single.flatMap(v -> completable.andThen(Single.just(v)))
Assuming you actually want to return the Single after the Completable, here's another way:
Using Java:
single.flatMap(x -> completable.toSingleDefault(x))
Using Kotlin:
single.flatMap { completable.toSingleDefault(it) }
Note that if you don't care whether the result is Single or Completable there is a special flatMapCompletable operator in RxJava2 to execute completable after Single:
single.flatMapCompletable(result -> completable);
If anyone is interested in a the RxSwift solution:
saveObjectsA().flatMap { (objectsA: [A]) -> Single<Bool> in
B.objects = objectsA
return completable.andThen(Single.just(true))
}
saveObjectsA returns a Single<[A]> which is an attribute of B (created previously). I needed to save it before saving B.