How to check if an ArrayList of Strings contains substrings of another ArrayList of Strings?

  • A+
Category:Languages
List<String> actualList = Arrays.asList ("mother has chocolate", "father has dog"); List<String> expectedList = Arrays.asList ("mother", "father", "son", "daughter"); 

Is there a way to check if expectedList contains any substrings of the strings in actualList?

I found a nested for-each solution:

public static boolean hasAny(List<String> actualList, List<String> expectedList) {     for (String expected: expectedList)         for (String actual: actualList)             if (actual.contains(expected))                 return true;      return false; } 

I was trying to a find lambda solution, but I could not. All the methods I found check for String#equals and not for String#contains.

It would be nice to have something like:

CollectionsUtils.containsAny(actualList, exptectedList); 

But it compares strings using String#equals not String#contains.

 


How about something like this:

list1.stream().allMatch(s1 -> list2.stream().anyMatch(s2 -> s1.contains(s2))) 

Try it online.

  • allMatch will check if everything is true
  • anyMatch will check if at least one is true

Here something similar in Java 7 style without lambdas and streams to understand a bit better what is going on:

boolean allMatch = true;        // Start allMatch at true for(String s1 : list1){   boolean anyMatch = false;     // Start anyMatch at false inside the loop   for(String s2 : list2){     anyMatch |= s1.contains(s2);// If any contains is true, anyMatch becomes/remains true     if(anyMatch){       break;     }   }   allMatch &= anyMatch;         // If any anyMatch is false, allMatch becomes false as well } return allMatch; 

EDIT: To make it a bit more efficient, anyMatch |= s1.contains(s2); could be if(anyMatch |= s1.contains(s2)) break; instead, since we won't need to continue the inner loop as soon as anyMatch becomes true.

Try it online.


If you prefer to have a CollectionsUtils.containsAny(list1, list2) you can reuse elsewhere in your code, you could always make one yourself:

public final class CollectionsUtil{   public static boolean containsAny(ArrayList<String> list1, ArrayList<String> list2){     return list1.stream().allMatch(s1 -> list2.stream().anyMatch(s2 -> s1.contains(s2)));     // Or the contents of the Java 7 check-method above if you prefer it   }    private CollectionsUtil(){     // Util class, so it's not initializable   } } 

Which can then be used as you wanted:

boolean result = CollectionsUtils.containsAny(actualList, expectedList); 

Try it online.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: