Better way to replace nested if else in Kotlin - kotlin

Is there any better way to replace below if else to more cleaner in Kotlin. I tried to replace with when statement but i couldn't match the logic.
if (!reached)
{
if (!info)
{
d.sinfo = extractinfo()
}
else
{
parserMessage("print something")
return d
}
info = true
}
else
{
if (d.media.isEmpty()){
parserMessage("print something")
return d
}
else{
if (d.media.at(d.media.size() - 1).media_information.isEmpty())
{d.media[d.media.size() - 1].minfo = extractinfo()}
else{
parserMessage("print something")
return d
}
}
}

Unless the code you have left out have some weird side effects, this code should be semantically equal:
when {
!reached && !info -> {
d.sinfo = extractinfo()
info = true
}
!reached && info -> {
parserMessage("print something")
return d
}
d.media.isEmpty() -> {
parserMessage("print something")
return d
}
d.media.at(d.media.size() - 1).media_information.isEmpty() -> {
d.media[d.media.size() - 1].minfo = extractinfo()
}
else -> {
parserMessage("print something")
return d
}
}
However, to say this, I had to fill in the gaps in the code you have presented myself, so I can't state this very confidently. It really helps your chances of getting a good answer if the code you want help with is runnable/understandable as presented.
By the way. This refactoring was partly done by pasting the code into IntelliJ and hitting Alt+Enter and choosing "Replace 'if' with 'when'" and "Flatten when"

Related

If else on Mono if empty or has value

This is the sample code
repo1.findById( id )
.map( p -> {
if( p == null ){
return repo2.findById( id ).flatMap( g -> {
g.setValue("some value");
return g;
});
}
else{
return repo3.findById( id ).flatMap( h -> {
h.setValue("some value");
return h;
});
}
});
Any better way to do this ?. If else inside flat map does not look neat to me.
The idiomatic approach would be to use the switchIfEmpty() operator.
You would only proceed to use the call to repo3 if repo1 actually returns a result.
If not data matches repo1.findById(id), then this call would return an empty result, not null.
To cover this case, use switchIfEmpty().
public Mono<Data> load(String id){
return repo1.findById(id)
.flatMap(p -> {
return repo3.findById(id)
.flatMap(h -> {
h.setValue("some value");
return h;
});
})
.switchIfEmpty(repo2.findById(id)
.flatMap(g -> {
g.setValue("some value");
return g;
}));
}

How to get object of Maximum value from LiveData?

I have liveData of market data. I want one market data object which have highest 'volume'. Here, volume is string value("277927.5793846733451135"), it could be null also.
I am using below code to achieve this. but, its not working.
viewModel.marketlist.observe(this as LifecycleOwner, { marketdata ->
val marketData = marketdata.getOrNull()
if(marketData !=null) {
val mData: MarketData? = marketData.marketData?.maxByOrNull { checkNotNull(it.volume) }
if (mData != null) {
binding.textViewPrice.text = mData.price
}
}
else {
//TODO
}
})
Any help would be appreciated!
You should be able to do something like this:
viewModel.marketList.observe(viewLifecycleOwner) { marketData ->
val maxData = marketData.getOrNull()?.marketData?.let { dataValues ->
dataValues.maxByOrNull { it.volume?.toDoubleOrNull() ?: -1.0 }
}
if (maxData != null) {
binding.textViewPrice.text = maxData.price
}
}
I cleaned up the observe call a bit, then I'm checking if marketData.getOrNull().marketData is null right away with my let { ... } block.
If you do have marketData (the inner one), it'll then safely call maxByOrNull { it.volume }.

How can I convert for loop to list functions in Kotlin

I'm reading The Big Nerd Ranch Guide and here is a question that wants you to use the list functions instead of for loop
var count = 0
for (answer in answerList) {
if (!answer.isCorrect) {
answer.isEnabled = false
answer.isSelected = false // deselect when answer is disabled
count++
if (count == 2) {
break
}
}
}
here is my solution, but I don't know how to deal with count
var count = 0
answerList
.filter { !it.isCorrect }
.forEach {
it.isSelected = false
it.isSelected = false
count++
}
.takeIf { count == 2 }
If you want to perform the actions for the first two (at most) items that are "not correct", you could do this, with take:
answerList
.filter { !it.isCorrect }
.take(2)
.forEach {
it.isEnabled = false
it.isSelected = false
}

How can I write do noting in Kotlin?

ESelect is a enum structure. I hope it will do noting when it is ESelect.NoAction in the following code.
It will cause compile error if I write ; after ESelect.NoAction ->, how can I fix it?
Code
aHomeViewModel.selectAction.observe(mLifecycleOwner, {
when(it) {
ESelect.SelectAll - > binding.chSelect.isChecked = true
ESelect.UnselectAll - > binding.chSelect.isChecked = false
ESelect.NoAction - > ; //It will do nothing
}
})
enum class ESelect {
SelectAll,
UnselectAll,
NoAction
}
You could return Unit (which is like void in Java). The code will look like:
aHomeViewModel.selectAction.observe(mLifecycleOwner, {
when(it) {
ESelect.SelectAll -> binding.chSelect.isChecked = true
ESelect.UnselectAll -> binding.chSelect.isChecked = false
ESelect.NoAction -> Unit
}
})
See the Docu: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/
You could use when as an expression instead of a statement, and for the NoAction case assign the existing value:
binding.chSelect.isChecked = when (it) {
ESelect.SelectAll -> true
ESelect.UnselectAll -> false
ESelect.NoAction -> binding.chSelect.isChecked
}
Or use if:
if (it == ESelect.SelectAll) {
binding.chSelect.isChecked = true
} else if (it == ESelect.UnselectAll) {
binding.chSelect.isChecked = false
}

break or return from when expressions

What I would like to do:
when(transaction.state) {
Transaction.Type.EXPIRED,
//about 10 more types
Transaction.Type.BLOCKED -> {
if (transaction.type == Transaction.Type.BLOCKED && transaction.closeAnyway) {
close(transaction)
break //close if type is blocked and has 'closeAnyway' flag
}
//common logic
}
//other types
}
I cannot write break:
'break' and 'continue' are not allowed in 'when' statements. Consider using labels to continue/break from the outer loop.
Is it a way to return/break from when statements? Or what is the best way to solve it?
You can use run with a return at label:
when(transaction.state) {
Transaction.Type.EXPIRED,
//about 10 more types
Transaction.Type.BLOCKED -> run {
if (transaction.type == Transaction.Type.BLOCKED && transaction.closeAnyway) {
close(transaction)
return#run //close if type is blocked and has 'closeAnyway' flag
}
//common logic
}
//other types
}
You can use labels to break/continue/return. e.g.:
transactions# for (transaction in transactions) {
when (transaction.state) {
Transaction.Type.EXPIRED,
Transaction.Type.BLOCKED -> {
break#transactions
}
}
}
See Returns and Jumps - Kotlin Programming Language for more details.
Work around using apply():
transaction.apply {
when(state) {
Transaction.Type.EXPIRED,
//about 10 more types
Transaction.Type.BLOCKED -> {
if (type == Transaction.Type.BLOCKED && closeAnyway) {
close(this)
return#apply
}
//common logic
}
//other types
}
}