break or return from when expressions - kotlin

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
}
}

Related

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 }.

Nextflow dynamic includes and output

I'm trying to use dynamic includes but I have problem to manage output files:
/*
* enables modules
*/
nextflow.enable.dsl = 2
include { requestData } from './modules/get_xapi_data'
include { uniqueActors } from './modules/unique_actors'
include { compileJson } from './modules/unique_actors'
if (params.user_algo) {
include { userAlgo } from params.user_algo
}
workflow {
dataChannel = Channel.from("xapi_data.json")
requestData(dataChannel)
uniqueActors(requestData.out.channel_data)
if (params.user_algo) {
user_algo = userAlgo(requestData.out.channel_data)
} else {
user_algo = null
}
output_json = [user_algo, uniqueActors.out]
// Filter output
Channel.fromList(output_json)
.filter{ it != null } <--- problem here
.map{ file(it) }
.set{jsonFiles}
compileJson(jsonFiles)
}
The problem is userAlgo can be dynamically loaded. And I don't know how I can take care of it. With this solution, I got a Unknown method invocation getFileSystem on ChannelOut type error.
The problem is that fromList expects a list of values, not a list of channels. If you use an empty Channel instead of checking for a null value, you could use:
if( params.user_algo ) {
user_algo = userAlgo(requestData.out.channel_data)
} else {
user_algo = Channel.empty()
}
user_algo
| concat( uniqueActors.out )
| map { file(it) }
| compileJson

Nested Loop select the minimum defined value asp.net

I have a list of states, which are defined to be ordered by min to max. the sequence is the following:
Cancelled - complete - draft - reservation - reserved - ordered - confirmed
So the cancelled is the minimum state, and confirmed is the maximum state. I may have different instances with different states, so I use a for-each loop to run through all states, and select the minimum state present in the loop.
That is: if in a list I have states [complete, reserved, draft, ordered] I need to check all the values and select complete -as it appears to be the minimum state. OR
if I have [reserved, confirmed, ordered, draft, cancelled, confirmed, confirmed] I need to select the cancelled value, as it appears to be the minimum.
I am doing the following check, but it does not seem to be working:
string globstatus = " ";
foreach (var currentstatus in list)
{
if (currentstatus == "cancelled")
{
globstatus = "cancelled";
}
else
{
if (globstatus == "cancelled")
{
return globstatus;
}
else
{
if (currentstatus == "complete")
{
globstatus = "complete";
}
else
{
if (globstatus == "complete")
{
return globstatus;
}
else
{
if (currentstatus == "draft")
{
globstatus = "draft";
}
else
{
if (globstatus == "reservation")
{
return globstatus;
}
else
{
if (currentstatus == "reserved")
{
globstatus = "reserved";
}
else
{
if (globstatus == "ordered")
{
return globstatus;
}
else
{
if (currentstatus == "confirmed")
{
globstatus = "confirmed";
}
else
{
return currentstatus;
}
}
}
}
}
}
}
}
}
}
return globstatus;
What can be the best solution to achieve the desired behavior?
I find a rule of thumb helpful that if I need more than three levels of braces, I need to rethink my code. It's hard to follow, easy to make mistakes, and a nightmare to debug. I suggest that applies here - trying to follow the flow of what all those nested if..else statements is extremely difficult.
Using Enum
My preferred solution is to achieve this using an Enum, e.g.:
var list = new List<Status>
{
Status.Complete,
Status.Draft,
Status.Draft,
Status.Confirmed
};
var minStatus = (Status)list.Select(l => (int)l).Min();
// minStatus = Status.Complete
public enum Status
{
Cancelled,
Complete,
Draft,
Reservation,
Reserved,
Ordered,
Confirmed
}
How it works: by default Enums give each value a zero-based integer, i.e. Cancelled = 0, Complete = 1 and so on. You can override this with your own values if you wish (e.g. 1/2/4/8/16 if you want to combine multiple values).
I recommend using Enum types for things like this, rather than strings. It helps avoid typos, gives someone else looking at your code a clear understanding of how your program works and its flow, and represents hierarchy in a way in which simple strings don't. (For example - does 'complete' come before or after 'draft'? Without context, I imagine most people would say after, but in this case it comes before - that is much more obvious when using an Enum.)
Parse strings to Enum
However if the statuses have to be strings, you could parse them into an enum like so:
var stringList = new List<string>
{
"complete",
"draft",
"draft",
"confirmed",
"this will be ignored"
};
var statusList = new List<int>();
foreach (var str in stringList)
{
if(Enum.TryParse(typeof(Status), str, ignoreCase: true, out object? parsed) && parsed is Status status)
{
statusList.Add((int)status);
}
}
var minStatus = (Status)statusList.Min();
// minStatus = Status.Complete
However, if it's possible to refactor your code to use the Enum in the first place, that would be a better solution, and much quicker as parsing strings has an overhead that would be good to avoid.

Better way to replace nested if else in 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"

How to write a custom FindElement routine in Selenium?

I'm trying to figure out how to write a custom FindElement routine in Selenium 2.0 WebDriver. The idea would be something like this:
driver.FindElement(By.Method( (ISearchContext) => {
/* examine search context logic here... */ }));
The anonymous method would examine the ISearchContext and return True if it matches; False otherwise.
I'm digging through the Selenium code, and getting a bit lost. It looks like the actual By.* logic is carried out server-side, not client side. That seems to be complicating matters.
Any suggestions?
I do a multi-staged search. I have a method that performs a try catch and then a method that gets the element. In theory you could do a try catch until instead of this way but I like this way better because of my setup.
public bool CheckUntil(IWebDriver driver, string selectorType, string selectorInfo)
{
int Timer = 160;
bool itemFound = false;
for (int i = 0; i < Timer; i++)
if(itemFound)
{
i = 0
}
else
{
Thread.Sleep(500);
if(selectorType.ToLower() == "id" && TryCatch(driver, selectorType, selectorInfo))
{
if(driver.FindElement(By.Id(selectorInfo).Displayed)
{
itemFound = true;
}
}
else if(selectorType.ToLower() == "tagname" && TryCatch(driver, selectorType, selectorInfo))
{
if(driver.FindElement(By.TagName(selectorInfo).Displayed)
{
itemFound = true;
}
}
}
return itemFound;
}
Here's my try catch method you can add as many different types as you want id, cssselector, xpath, tagname, classname, etc.
public bool TryCatch(IWebDriver driver, string selectorType, string selectorInfo)
{
bool ElementFound = false;
try
{
switch(selectorType)
{
case "id":
driver.FindElement(By.Id(selectorInfo);
break;
case "tagname":
driver.FindElement(By.TagName(selectorInfo);
break;
}
ElementFound = truel
}
catch
{
ElementFound = false;
}
return ElementFound;
}
Ok, I figured out how to do this. I'm leveraging driver.ExecuteScript() to run custom js on the webdriver. It looks a bit like this:
function elementFound(elem) {
var nodeType = navigator.appName == ""Microsoft Internet
Explorer"" ? document.ELEMENT_NODE : Node.ELEMENT_NODE;
if(elem.nodeType == nodeType)
{
/* Element identification logic here */
}
else { return false; }
}
function traverseElement(elem) {
if (elementFound(elem) == true) {
return elem;
}
else {
for (var i = 0; i < elem.childNodes.length; i++) {
var ret = traverseElement(elem.childNodes[i]);
if(ret != null) { return ret; }
}
}
}
return traverseElement(document);