如何在给定列表中找到匹配项
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
).
我想编写一个方法,将 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
). - 将谓词与 和 (
&&
) 组合的基础必须 returntrue
因为只有这样结果才不会受到影响(和&&
所有条件需要求值到true
,整体结果才能是true
).