Compare one String with multiple values in one expression

JavaRegexString

Java Problem Overview


I have one String variable, str with possible values, val1, val2 and val3.

I want to compare (with equal case) str to all of these values using an if statement, for example:

if("val1".equalsIgnoreCase(str)||"val2".equalsIgnoreCase(str)||"val3".equalsIgnoreCase(str))
{
      //remaining code
}

Is there a way to avoid using multiple OR (||) operators and compare values in one expression? For example, like this:

 if(("val1" OR "val2" OR "val3").equalsIgnoreCase(str)   //this is only an idea.

Java Solutions


Solution 1 - Java

I found the better solution. This can be achieved through RegEx:

if (str.matches("val1|val2|val3")) {
     // remaining code
}

For case insensitive matching:

if (str.matches("(?i)val1|val2|val3")) {
     // remaining code
}

Solution 2 - Java

In Java 8+, you might use a Stream<T> and anyMatch(Predicate<? super T>) with something like

if (Stream.of("val1", "val2", "val3").anyMatch(str::equalsIgnoreCase)) {
	// ...
}

	

Solution 3 - Java

You could store all the strings that you want to compare str with into a collection and check if the collection contains str. Store all strings in the collection as lowercase and convert str to lowercase before querying the collection. For example:

Set<String> strings = new HashSet<String>();
strings.add("val1");
strings.add("val2");

String str = "Val1";

if (strings.contains(str.toLowerCase()))
{
}

Solution 4 - Java

Yet another alternative (kinda similar to https://stackoverflow.com/a/32241628/6095216 above) using StringUtils from the apache commons library: https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#equalsAnyIgnoreCase-java.lang.CharSequence-java.lang.CharSequence...-

if (StringUtils.equalsAnyIgnoreCase(str, "val1", "val2", "val3")) {
  // remaining code
}

Solution 5 - Java

Here a performance test with multiples alternatives (some are case sensitive and others case insensitive):

public static void main(String[] args) {
    // Why 4 * 4:
    // The test contains 3 values (val1, val2 and val3). Checking 4 combinations will check the match on all values, and the non match;
    // Try 4 times: lowercase, UPPERCASE, prefix + lowercase, prefix + UPPERCASE;
    final int NUMBER_OF_TESTS = 4 * 4;
    final int EXCUTIONS_BY_TEST = 1_000_000;
    int numberOfMatches;
    int numberOfExpectedCaseSensitiveMatches;
    int numberOfExpectedCaseInsensitiveMatches;
    // Start at -1, because the first execution is always slower, and should be ignored!
    for (int i = -1; i < NUMBER_OF_TESTS; i++) {
        int iInsensitive = i % 4;
        List<String> testType = new ArrayList<>();
        List<Long> timeSteps = new ArrayList<>();
        String name = (i / 4 > 1 ? "dummyPrefix" : "") + ((i / 4) % 2 == 0 ? "val" : "VAL" )+iInsensitive ;
        numberOfExpectedCaseSensitiveMatches = 1 <= i && i <= 3 ? EXCUTIONS_BY_TEST : 0;
        numberOfExpectedCaseInsensitiveMatches = 1 <= iInsensitive && iInsensitive <= 3 && i / 4 <= 1 ? EXCUTIONS_BY_TEST : 0;
        timeSteps.add(System.currentTimeMillis());
        //-----------------------------------------
        numberOfMatches = 0;
        testType.add("List (Case sensitive)");
        for (int j = 0; j < EXCUTIONS_BY_TEST; j++) {
            if (Arrays.asList("val1", "val2", "val3").contains(name)) {
                numberOfMatches++;
            }
        }
        if (numberOfMatches != numberOfExpectedCaseSensitiveMatches) {
            throw new RuntimeException();
        }
        timeSteps.add(System.currentTimeMillis());

        //-----------------------------------------
        numberOfMatches = 0;
        testType.add("Set (Case sensitive)");
        for (int j = 0; j < EXCUTIONS_BY_TEST; j++) {
            if (new HashSet<>(Arrays.asList(new String[] {"val1", "val2", "val3"})).contains(name)) {
                numberOfMatches++;
            }
        }
        if (numberOfMatches != numberOfExpectedCaseSensitiveMatches) {
            throw new RuntimeException();
        }
        timeSteps.add(System.currentTimeMillis());

        //-----------------------------------------
        numberOfMatches = 0;
        testType.add("OR (Case sensitive)");
        for (int j = 0; j < EXCUTIONS_BY_TEST; j++) {
            if ("val1".equals(name) || "val2".equals(name) || "val3".equals(name)) {
                numberOfMatches++;
            }
        }
        if (numberOfMatches != numberOfExpectedCaseSensitiveMatches) {
            throw new RuntimeException();
        }
        timeSteps.add(System.currentTimeMillis());

        //-----------------------------------------
        numberOfMatches = 0;
        testType.add("OR (Case insensitive)");
        for (int j = 0; j < EXCUTIONS_BY_TEST; j++) {
            if ("val1".equalsIgnoreCase(name) || "val2".equalsIgnoreCase(name) || "val3".equalsIgnoreCase(name)) {
                numberOfMatches++;
            }
        }
        if (numberOfMatches != numberOfExpectedCaseInsensitiveMatches) {
            throw new RuntimeException();
        }
        timeSteps.add(System.currentTimeMillis());

        //-----------------------------------------
        numberOfMatches = 0;
        testType.add("ArraysBinarySearch(Case sensitive)");
        for (int j = 0; j < EXCUTIONS_BY_TEST; j++) {
            if (Arrays.binarySearch(new String[]{"val1", "val2", "val3"}, name) >= 0) {
                numberOfMatches++;
            }
        }
        if (numberOfMatches != numberOfExpectedCaseSensitiveMatches) {
            throw new RuntimeException();
        }
        timeSteps.add(System.currentTimeMillis());

        //-----------------------------------------
        numberOfMatches = 0;
        testType.add("Java8 Stream (Case sensitive)");
        for (int j = 0; j < EXCUTIONS_BY_TEST; j++) {
            if (Stream.of("val1", "val2", "val3").anyMatch(name::equals)) {
                numberOfMatches++;
            }
        }
        if (numberOfMatches != numberOfExpectedCaseSensitiveMatches) {
            throw new RuntimeException();
        }
        timeSteps.add(System.currentTimeMillis());

        //-----------------------------------------
        numberOfMatches = 0;
        testType.add("Java8 Stream (Case insensitive)");
        for (int j = 0; j < EXCUTIONS_BY_TEST; j++) {
            if (Stream.of("val1", "val2", "val3").anyMatch(name::equalsIgnoreCase)) {
                numberOfMatches++;
            }
        }
        if (numberOfMatches != numberOfExpectedCaseInsensitiveMatches) {
            throw new RuntimeException();
        }
        timeSteps.add(System.currentTimeMillis());

        //-----------------------------------------
        numberOfMatches = 0;
        testType.add("RegEx (Case sensitive)");
        // WARNING: if values contains special characters, that should be escaped by Pattern.quote(String)
        for (int j = 0; j < EXCUTIONS_BY_TEST; j++) {
            if (name.matches("val1|val2|val3")) {
                numberOfMatches++;
            }
        }
        if (numberOfMatches != numberOfExpectedCaseSensitiveMatches) {
            throw new RuntimeException();
        }
        timeSteps.add(System.currentTimeMillis());

        //-----------------------------------------
        numberOfMatches = 0;
        testType.add("RegEx (Case insensitive)");
        // WARNING: if values contains special characters, that should be escaped by Pattern.quote(String)
        for (int j = 0; j < EXCUTIONS_BY_TEST; j++) {
            if (name.matches("(?i)val1|val2|val3")) {
                numberOfMatches++;
            }
        }
        if (numberOfMatches != numberOfExpectedCaseInsensitiveMatches) {
            throw new RuntimeException();
        }
        timeSteps.add(System.currentTimeMillis());

        //-----------------------------------------
        numberOfMatches = 0;
        testType.add("StringIndexOf (Case sensitive)");
        // WARNING: the string to be matched should not contains the SEPARATOR!
        final String SEPARATOR = ",";
        for (int j = 0; j < EXCUTIONS_BY_TEST; j++) {
            // Don't forget the SEPARATOR at the begin and at the end!
            if ((SEPARATOR+"val1"+SEPARATOR+"val2"+SEPARATOR+"val3"+SEPARATOR).indexOf(SEPARATOR + name + SEPARATOR)>=0) {
                numberOfMatches++;
            }
        }
        if (numberOfMatches != numberOfExpectedCaseSensitiveMatches) {
            throw new RuntimeException();
        }
        timeSteps.add(System.currentTimeMillis());

        //-----------------------------------------
        StringBuffer sb = new StringBuffer("Test ").append(i)
                .append("{ name : ").append(name)
                .append(", numberOfExpectedCaseSensitiveMatches : ").append(numberOfExpectedCaseSensitiveMatches)
                .append(", numberOfExpectedCaseInsensitiveMatches : ").append(numberOfExpectedCaseInsensitiveMatches)
                .append(" }:\n");
        for (int j = 0; j < testType.size(); j++) {
            sb.append(String.format("    %4d ms with %s\n", timeSteps.get(j + 1)-timeSteps.get(j), testType.get(j)));
        }
        System.out.println(sb.toString());
    }
}

Output (only the worse case, that is when have to check all elements without match none):

Test 4{ name : VAL0, numberOfExpectedCaseSensitiveMatches : 0, numberOfExpectedCaseInsensitiveMatches : 0 }:
  43 ms with List (Case sensitive)
 378 ms with Set (Case sensitive)
  22 ms with OR (Case sensitive)
 254 ms with OR (Case insensitive)
  35 ms with ArraysBinarySearch(Case sensitive)
 266 ms with Java8 Stream (Case sensitive)
 531 ms with Java8 Stream (Case insensitive)
1009 ms with RegEx (Case sensitive)
1201 ms with RegEx (Case insensitive)
 107 ms with StringIndexOf (Case sensitive)

Output provided by Warpspeed SCP, changing the test to fill the collections outside of the loops, simulationg the code when the list of values to test never change (and the collections can be cached).

(don't compare the time of this test with the previous test, since it was executed on different environment, but compare only the time of different strategies for the same test):

Test 4{ name : VAL0, numberOfExpectedCaseSensitiveMatches : 0, numberOfExpectedCaseInsensitiveMatches : 0 }:
    26 ms with List (Case sensitive)
    6 ms with Set (Case sensitive)
    12 ms with OR (Case sensitive)
    371 ms with OR (Case insensitive)
    14 ms with ArraysBinarySearch(Case sensitive)
    100 ms with Java8 Stream (Case sensitive)
    214 ms with Java8 Stream (Case insensitive)
    773 ms with RegEx (Case sensitive)
    946 ms with RegEx (Case insensitive)
    37 ms with StringIndexOf (Case sensitive)

Solution 6 - Java

ArrayUtils may be helpful.

ArrayUtils.contains(new String[]{"1", "2"}, "1")

Solution 7 - Java

Small enhancement to perfectly valid @hmjd's answer: you can use following syntax:

class A {

  final Set<String> strings = new HashSet<>() {{
    add("val1");
    add("val2");
  }};

  // ...

  if (strings.contains(str.toLowerCase())) {
  }

  // ...
}

It allows you to initialize you Set in-place.

Solution 8 - Java

Just use var-args and write your own static method:

public static boolean compareWithMany(String first, String next, String ... rest)
{
    if(first.equalsIgnoreCase(next))
        return true;
    for(int i = 0; i < rest.length; i++)
    {
        if(first.equalsIgnoreCase(rest[i]))
            return true;
    }
    return false;
}

public static void main(String[] args)
{
    final String str = "val1";
    System.out.println(compareWithMany(str, "val1", "val2", "val3"));
}

Solution 9 - Java

Apache Commons Collection class.

StringUtils.equalsAny(CharSequence string, CharSequence... searchStrings)

So in your case, it would be

StringUtils.equalsAny(str, "val1", "val2", "val3");

Solution 10 - Java

Starting from Java 9, you can use either of following

List.of("val1", "val2", "val3").contains(str.toLowerCase())

Set.of("val1", "val2", "val3").contains(str.toLowerCase());

Solution 11 - Java

The are many solutions suggested and most are working solutions. However i must add here that people suggesting using regex i.e str.matches("val1|val2|val3") is okay however

  1. it's not performant if the method/code is called many times
  2. it's not null safe

I would suggest to use apache commons lang3 stringUtils StringUtils.equalsAny(str, "val1", "val2", "val3") instead

Test:

public static void main(String[] args) {
        String var = "val1";
        long t, t1 = 0, t2 = 0;

        for (int i = 0; i < 1000; i++) {
            t = System.currentTimeMillis();
            var.matches("val1|val2|val3");
            t1 += System.currentTimeMillis() - t;

            t = System.currentTimeMillis();
            StringUtils.equalsAny(var, "val1", "val2", "val3");
            t2 += System.currentTimeMillis() - t;
        }
        System.out.println("Matches took + " + t1 + " ms\nStringUtils took " + t2 + " ms");
    }

Results after 1000 iteration:

Matches took + 18 ms
StringUtils took 7 ms

Solution 12 - Java

For those who came here for exact equality checks (not ignoring case), I find that

if (Arrays.asList(str1, str2, str3).contains(strToCheck)) {
    ...
}

is one of, if the most concise solution, and is available on Java 7.

Solution 13 - Java

You can achieve this with Collections framework. Put all your options in a Collection say something like Collection<String> options ;

Then loop throgh this to compare your string with the list elements and if it is you can return a boolean value true and otherwise false.

Solution 14 - Java

Remember in Java a quoted String is still a String object. Therefore you can use the String function contains() to test for a range of Strings or integers using this method:

if ("A C Viking G M Ocelot".contains(mAnswer)) {...}

for numbers it's a tad more involved but still works:

if ("1 4 5 9 10 17 23 96457".contains(String.valueOf(mNumAnswer))) {...} 

Solution 15 - Java

Sorry for reponening this old question, for Java 8+ I think the best solution is the one provided by Elliott Frisch (Stream.of("str1", "str2", "str3").anyMatches(str::equalsIgnoreCase)) but it seems like it's missing one of the simplest solution for eldest version of Java:

if(Arrays.asList("val1", "val2", "val3", ..., "val_n").contains(str.toLowerCase())){
//...
}

You could apply some error prevenction by checking the non-nullity of variable str, and by caching the list once created.

// List of lower-case possibilities
final List<String> list = Arrays.asList("val1", "val2", "val3", ..., "val_n");
for(String str : somethingYouCouldTheReadStringFrom()){
  if(str != null && list.contains(str.toLowerCase())){
    //...
  }
}

Solution 16 - Java

Since this question has been reopened anyway, I might just as well propose an enum solution.

enum ValidValues {
   VAL1, VAL2, VAL3;

   public static boolean isValid(String input) {
       return Stream.of(ValidValues.values())
                    .map(ValidValues::name)
                    .anyMatch(s -> s.equalsIgnoreCase(input));
   }
}

Or you can just use the stream statement with

Stream.of("val1", "val2", "val3")
      .anyMatch(s -> s.equalsIgnoreCase(str))

if you only use it in one place.

Solution 17 - Java

!string.matches("a|b|c|d") 

works fine for me.

Solution 18 - Java

No, there is no such possibility. Allthough, one could imagine:

public static boolean contains(String s, Collection<String>c) {
    for (String ss : c) {
       if (s.equalsIgnoreCase(ss)) return true;
    }
    return false;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionkundan boraView Question on Stackoverflow
Solution 1 - Javakundan boraView Answer on Stackoverflow
Solution 2 - JavaElliott FrischView Answer on Stackoverflow
Solution 3 - JavahmjdView Answer on Stackoverflow
Solution 4 - JavaYuryView Answer on Stackoverflow
Solution 5 - JavaManuel RomeiroView Answer on Stackoverflow
Solution 6 - JavaJeffrey4lView Answer on Stackoverflow
Solution 7 - JavaAndrey StarodubtsevView Answer on Stackoverflow
Solution 8 - JavaNeetView Answer on Stackoverflow
Solution 9 - JavaVivek DixitView Answer on Stackoverflow
Solution 10 - JavaAnkushView Answer on Stackoverflow
Solution 11 - Javauser2083529View Answer on Stackoverflow
Solution 12 - JavaDrackmordView Answer on Stackoverflow
Solution 13 - JavaTKVView Answer on Stackoverflow
Solution 14 - JavaStuart WalshView Answer on Stackoverflow
Solution 15 - JavaMarco Carlo MoriggiView Answer on Stackoverflow
Solution 16 - JavadaniuView Answer on Stackoverflow
Solution 17 - JavaBruView Answer on Stackoverflow
Solution 18 - JavaslipsetView Answer on Stackoverflow