Как мне найти список строк внутри другой строки? - PullRequest
0 голосов
/ 13 сентября 2018

Вот код, который работает, но выглядит не элегантно. Как лучше искать любое вхождение этих строк в другую строку?

String AndyDaltonInjury = "broken right thumb";

if (AndyDaltonInjury.toLowerCase().contains("broken") &&
    (AndyDaltonInjury.toLowerCase().contains("knee") ||
    AndyDaltonInjury.toLowerCase().contains("leg")   ||
    AndyDaltonInjury.toLowerCase().contains("ankle") ||
    AndyDaltonInjury.toLowerCase().contains("thumb") ||
    AndyDaltonInjury.toLowerCase().contains("wrist"))) 
{
    System.out.println("Marvin sends in the backup quarterback.");  
}

Ответы [ 5 ]

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

Алгоритмы, основанные на хеше, вероятно, дадут вам лучшую производительность, если вам нужно будет проверять большое количество текста на наличие вхождений в огромном наборе

HashSet будет хорошей первой попыткой, поскольку поиск (проверка, содержится ли ключ в наборе) будет между O (1) и O (n).

Тем не менее, я бы настоятельно рекомендовал изучить преимущества использования [Bloom Filter][1].Он будет хорошо служить в качестве предварительного фильтра, поскольку он обеспечивает предсказуемую производительность O (k).Поскольку фильтр будет иметь небольшой процент ложных срабатываний, вам также потребуется запустить второй этап.

Посмотрите на Guava BloomFilter для хорошей реализации.

Еще одно преимущество фильтра Блума состоит в том, что он не содержит исходного набора данных, а представляет собой только уменьшенный хеш, что означает, что его размер минимален.Это означает, что он больше подходит для распределенных систем, поскольку копирует очень эффективно.В такой среде, как Apache Spark, вы бы даже установили ее как переменную широковещания, поскольку после ее создания она обычно постоянна во времени.

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

Вы можете попробовать это:

String test = "broken right thumb";

Predicate << ? super String > machCriteria = s - > Stream.of("knee", "leg", "ankle", "thumb", "wrist").anyMatch(e - > e.equals(s.toLowerCase()));
String result = Pattern.compile(" ").splitAsStream(test).anyMatch(machCriteria) ? "Marvin sends in the backup quarterback." : "";
System.out.println(result);
0 голосов
/ 13 сентября 2018

В качестве альтернативы уже опубликованному решению на основе множеств (которое, на мой взгляд, лучше в смысле читабельности), это можно сделать с помощью регулярного выражения:

final Pattern brokeStuffPattern = Pattern.compile(
    ".*\\bbroken?\\b.*\\b(?:knee|leg|ankle|thumb|wrist)s?\\b.*"
    + "|.*\\b(?:knee|leg|ankle|thumb|wrist)s?\\b.*\\bbroken?\\b.*",
    Pattern.CASE_INSENSITIVE
);
if (brokeStuffPattern.matcher(AndyDaltonInjury).matches()) {
    ...
}

Это будетучитывать множественное число и идеальное время глагола, например, если бы соответствовал "сломанным ногам".

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

Вы можете создать отсутствующие функции (содержащие все / любые) как методы или выразить их с помощью лямбда-нотаций:

BiPredicate<String, List<String>> containsAll = (text, words) -> 
    words.stream().allMatch(word -> text.toLowerCase().contains(word));
BiPredicate<String, List<String>> containsAny = (text, words) -> 
    words.stream().anyMatch(word -> text.toLowerCase().contains(word));

if (containsAll.test(AndyDaltonInjury, Arrays.asList("broken")) && 
    containsAny.test(AndyDaltonInjury, Arrays.asList("knee", "leg", "ankle", "thumb", "wrist"))) {
    System.out.println("Marvin sends in the backup quarterback.");
}
0 голосов
/ 13 сентября 2018

Используйте коллекцию Set и ее метод Set::contains insde Streaming массива разбиения с разделителем пробела (" "):

Set<String> set = new HashSet<>(Arrays.asList("knee", "leg", "ankle", "thumb", "wrist"));

String lower = "broken right thumb".toLowerCase();
String split[] = lower.split(" ");
if (lower.contains("broken") && Arrays.stream(split).anyMatch(set::contains)) {
    System.out.println("Marvin sends in the backup quarterback.");
}

Кроме того, я настоятельно рекомендую вам использовать имена переменных в нижнем регистре.

...