How to replace multiple if-else statements to optimize code?
Asked Answered
H

3

5

I want to know if there is any way i could optimize this code.

String[] array;
for(String s:array){
   if(s.contains("one"))
       //call first function
   else if(s.contains("two"))
      //call second function
   ...and so on
}

The string is basically lines I am reading from a file.So there can be many number of lines.And I have to look for specific keywords in those lines and call the corresponding function.

Hangup answered 18/10, 2016 at 13:50 Comment(15)
You can use Switch Case instead.. Nothing other can help you!!!Poitiers
How can switch case help in this case.? I have a string line in which i am checking for substring. Its not "exact matching".Hangup
What are the functions like? Do the all have the same signature?Retard
function is basically a symbol for the operation that i am going to perform. If the line contains the substring then i use line.substring() to extract specific information that i need.Hangup
By "optimize", do you mean that you want it to run faster? Are you having a performance problem?Carpi
If it can be made faster then great. But mostly I am looking to reduce the size of this code because I have to use muliple if-else statements.Hangup
Are you using Java 8? it may be possible to do something with lambdasArlettearley
I'd use regex. Your pattern can then be set to match as many as you want and do it all within one .matches() call. Example regex: one|two|threeLapin
Yes, I am using Java8. Can you provide some relevant link?Hangup
@Lapin the substrings can be space separated values with special characters. How would regex work there. Can you provide an exampleHangup
flkes made the answer I was going to do.Arlettearley
is this order dependent? For example, if the string is "this is two and one" do you only "call first function"?Blackguard
For spaces and special characters, use escape sequences. For example: one\ two|three\ four|five will match "one two", "three four" and "five". For other special characters, do some Googling about Regex.Lapin
just imagine the case you are getting to like eighteen you would Trigger ´else if(s.contains("eight")) }´ and ´else if(s.contains("teighteen")) }´Languorous
@flkes there will be not overlapping. so no not order dependentHangup
B
5

This wont stop you code from doing many String#contains calls, however, it will avoid the if/else chaining..

You can create a key-function map and then iterate over the entries of this map to find which method to call.

public void one() {...}
public void two() {...}
private final Map<String, Runnable> lookup = new HashMap<String, Runnable>() {{
    put("one", this::one);
    put("two", this::two);
}};

You can then iterate over the entry-set:

for(final String s : array) {
    for(final Map.Entry<String, Runnable> entry : lookup) {
        if (s.contains(entry.getKey())) {
            entry.getValue().run();
            break;
        }
    }
}
Blackguard answered 18/10, 2016 at 14:10 Comment(8)
this will certainly degrade the performance as now I will have to loop over the entire map to get the function i need to call. Thanks anywaysHangup
On second thoughts, with few manipulations this will serve my purpose.Hangup
On second thought, with a few tweaks this will server my purpose. +1 for answerHangup
There is no reason to use a TreeMap here, iterating over a HashMap is likely to be faster, as its based on a flat array. Further, there is no reason to create an entire subclass just to save typing lookup. two times (or once per entry). @Anurag: this code doesn’t iterate over the entire map, it stops at the first match, so there’s no performance difference to your original if … else if … sequence.Boomer
@Boomer in the begining I assumed the if else blocks were order dependant- later OP said they are not. So yes i agree that hashmap would be a better choice!Blackguard
Well, it would be a property of the contrived example that "one" is smaller than "two" in lexicographic order, but it would be pure luck, if the order imposed by TreeMap matches the program order of the original if … else if … statements for the actual keywords. If maintaining the lookup order is required, using a LinkedHashMap and putting in the desired order would be the more natural choice.Boomer
You just need to do get on the map to get the function to call. This is the correct answerGooseflesh
@Peter Gelderbloem: just using get doesn’t work as we’re not looking up a match, but a substring. So iterating over the candidates and calling contains is unavoidable. Or you use the regex variant of my answer to get the matching string. Then, you could use get on a Map instead of using switch, whatever you prefer…Boomer
R
1

You can use switch, but in this case i think the if else is the best way

Ruysdael answered 18/10, 2016 at 14:11 Comment(0)
B
1

Since you stated that the order of the checks is not important, you can use a combination of regular expression matching and switch:

static final Pattern KEYWORDS=Pattern.compile("one|two|tree|etc");

 

Matcher m=KEYWORDS.matcher("");
for(String s:array) {
    if(m.reset(s).find()) switch(m.group()) {
        case "one": //call first function
            break;
        case "two": //call second function
            break;
        case "three": //call third function
            break;
        case "etc": // etc
            break;
    }
}

Since this will stop at the first match, regardless of which keyword, it is potentially more efficient than checking one keyword after another, for strings containing a match close to the beginning.

Boomer answered 19/10, 2016 at 16:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.