Как проверить, содержит ли ArrayList of Strings подстроки другого ArrayList of Strings? - PullRequest
0 голосов
/ 27 сентября 2018
List<String> actualList = Arrays.asList ("mother has chocolate", "father has dog");
List<String> expectedList = Arrays.asList ("mother", "father", "son", "daughter");

Есть ли способ проверить, содержит ли expectedList какие-либо подстроки строк в actualList?

Я нашел вложенное решение для каждого:

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

Я пытался найти лямбда-решение, но не смог.Все методы, которые я нашел, проверяют на String#equals, а не на String#contains.

Было бы неплохо иметь что-то вроде:

CollectionsUtils.containsAny(actualList, exptectedList);

Но он сравнивает строки, используя String#equals, а неString#contains.

РЕДАКТИРОВАТЬ:

На основе вопросов: я хочу получить TRUE, если ВСЕ подстроки из actualList являются частью Ожидаемый список.И решение от Кевина ниже работает для меня.

Ответы [ 4 ]

0 голосов
/ 27 сентября 2018

Я на 99% уверен, что вы не ищете hasAny как наиболее часто задаваемый ответ здесь, но вместо этого вы хотите увидеть, содержатся ли все из expectedList в какой-либо строке в actualList.Для этого было бы полезно сначала создать Set и работать с ним (поскольку contains равно O(1) для HashSet и противопоставлено O(n) для List).

Подумайте отеперь, поскольку все, что вам нужно, это contains, вы можете разделить этот actualList и создать из него уникальные слова:

private static boolean test(List<String> actualList, List<String> expectedList) {

    Pattern p = Pattern.compile("\\s+");

    Set<String> set = actualList.stream()
            .flatMap(p::splitAsStream)
            .collect(Collectors.toSet());

    return expectedList.stream().allMatch(set::contains);

}
0 голосов
/ 27 сентября 2018
public static boolean containsAny(List<String> actualList, List<String> expectedList) {
    final Pattern words = Pattern.compile("\\s+");
    return actualList.stream()
                     .flatMap(words::splitAsStream)
                     .distinct()
//                     .allMatch(expectedList::contains)
                     .anyMatch(expectedList::contains);
}
0 голосов
/ 27 сентября 2018

Ответ Кевина лучше, но другой подход заключается в переопределении метода equal объекта Wrapper.

import org.springframework.util.CollectionUtils;

class Holder {
    public String obj;

    public Holder(String obj) {
        this.obj = obj;
    }

    @Override
    public boolean equals(Object holder) {
        if (!(holder instanceof Holder))
            return false;

        Holder newH = ((Holder) holder);

        if (newH == null || newH.obj == null || obj == null)
            return false;

        return obj.contains(newH.obj) || newH.obj.contains(obj);  //actually it's should be one directed.
    }
}

CollectionUtils.containsAny(
            actual.stream().map(Holder::new).collect(Collectors.toList()),
            expected.stream().map(Holder::new).collect(Collectors.toList())
    );
0 голосов
/ 27 сентября 2018

Примерно так:

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

Попробуйте онлайн.

  • allMatch проверит все лиis true
  • anyMatch проверит, является ли хотя бы один true

Здесь что-то похожее в стиле Java 7 без лямбд и потоков, чтобы немного лучше понять, чтопроисходит:

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 true as well
    if(anyMatch)               // And stop the inner loop as soon as we've found a match
      break;
  }
  allMatch = anyMatch;         // If any anyMatch is false, allMatch becomes false as well
  if(!allMatch)                // And stop the outer loop as soon as we've found a mismatch
    break;
}
return allMatch;

Попробуйте онлайн.


Если вы предпочитаете иметь CollectionsUtils.containsAny(list1, list2), вы можете использовать его в другом местев своем коде вы всегда можете сделать его самостоятельно:

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

Который затем можно использовать по своему усмотрению:

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

Попробуйте онлайн.

...