如何在给定列表中找到匹配项

How to find the matches in the given List

我想编写一个方法,将 String key 以空格分隔,并在其中搜索匹配项的 String 列表作为输入。

字符串 key 的格式可能是这样的:

"s1 or s2 s3 or s4"

必须翻译成条件"(s1 or s2) and (s3 or s4)", 其中用 or 分组的条件总是先执行。

该方法应该return从指定的“键”中获得符合条件的字符串列表。

public List<String> search(String key, ArrayList<String> s){
    ...
}

输入示例(一个key和一个列表):

// if ((s.contains("i") || s.contains("you")) && (s.contains("boy") || s.contains("girl")) then store in the List and return finally
String key = "i or you boy or girl"; 

ArrayList<String> s = new ArrayList<String>(
            Arrays.asList("hello world",
                          "i am a boy",
                          "i am a girl"));

那么结果列表将包含字符串:

`"i am a boy"` and `"i am a girl"`.

可以用predicates布尔条件表示的函数)和正则表达式.

总体思路是根据字符串 key 生成一个 Predicate,然后根据该谓词测试列表元素。

解析 Predicate 的过程按以下步骤完成:

  • 根据以下正则表达式"(?<!or)\s+(?!or)",将密钥拆分成组,之后必须与逻辑AND组合
    • (?<!or) - negative lookbehind,表示匹配字符串之前的一组字符,不能等于"or";
    • (?!or) - negative lookahead,表示匹配字符串后的字符组不能等于"or";
    • \s+ - 匹配由一个或多个 空格.
    • 组成的字符串
  • 将上一步得到的每组字符串在" or "上进行拆分,将得到的谓词与OR.
  • 进行逻辑组合
  • 将上一步生成的谓词组合成一个谓词。

(有关正则表达式的信息,请查看 this tutorial)

然后我们需要遍历给定的列表并将组合谓词的方法 test() 应用于每个元素。符合谓词的元素将被添加到结果列表中。

public static void main(String[] args) {
    String key = "i or you boy or girl";

    List<String> source =
            List.of("hello world", "i am a boy", "i am a girl");

    Predicate<String> predicate = getPredicate(key);
    List<String> result = new ArrayList<>();

    for (String next: source) {
        if (predicate.test(next)) {
            result.add(next);
        }
    }
    System.out.println(result);
}

public static Predicate<String> getPredicate(String key) {
    Predicate<String> result = str -> true;

    for (String next: key.split("(?<!or)\s+(?!or)")) {
        Predicate<String> pred = str -> false;

        for (String target: next.strip().split(" or ")) {
            if (target.isEmpty()) {
                continue;
            }
            pred = pred.or(str -> str.contains(target));
        }
        result = result.and(pred);
    }
    return result;
}

输出

[i am a boy, i am a girl]

注:

  • 用于将谓词与 (||) 组合的基础必须产生 false 因为只有在这种情况下它才不会影响结果 ( with(||)只有一个条件可以true,整体结果会被评估为true).
  • 将谓词与 (&&) 组合的基础必须 return true 因为只有这样结果才不会受到影响( && 所有条件需要求值到true,整体结果才能是 true).