- 在流之前对列表进行排序。
- 使用
IntStream,找到匹配过滤器"X".equals(a)的第一个元素的索引
- 如果找到这样的索引,检查索引之前的所有元素是否匹配另一个过滤器
"Y".equals(a)
static Test findFirstAfterAll(String first, String all, List<Test> testList) {
testList.sort(Comparator.comparingInt(Test::getSortKey));
int index = IntStream
.range(0, testList.size())
.filter(i -> first.equals(testList.get(i).getA()))
.findFirst()
.orElse(-1);
return IntStream.range(0, index)
.allMatch(i -> all.equals(testList.get(i).getA()))
? testList.get(index) : null;
}
测试:
List<Test> testList = Arrays.asList(
new Test("X", 20),
new Test("Y", 15),
new Test("Y", 12)
);
System.out.println(findFirstAfterAll("X", "Y", testList));
输出:
Test(a=X, sortKey=20)
假设 a.equals("Y") 的 no 元素可能出现在“X”之前,使用 Java 9 Stream::takeWhile 也可以工作:
static Optional<Test> findFirstAfterAll(String first, String all, List<Test> testList) {
return testList.stream()
.sorted(Comparator.comparingInt(Test::getSortKey))
.takeWhile(t -> all.equals(t.getA()) || first.equals(t.getA()))
.filter(t -> first.equals(t.getA()))
.findFirst();
}
测试:
System.out.println(findFirstAfterAll("X", "Y", Arrays.asList(new Test("Y", 20), new Test("X", 15), new Test("X", 12))));
System.out.println(findFirstAfterAll("X", "Y", Arrays.asList(new Test("X", 20), new Test("Y", 15), new Test("Y", 12))));
System.out.println(findFirstAfterAll("X", "Y", Arrays.asList(new Test("Y", 20), new Test("Y", 15), new Test("Y", 12))));
System.out.println(findFirstAfterAll("X", "Y", Arrays.asList(new Test("Y", 20), new Test("X", 15), new Test("A", 12))));
输出:
Optional[Test{a='X', sortKey=12}]
Optional[Test{a='X', sortKey=20}]
Optional.empty
Optional.empty
逻辑是只有“X”或“Y”可能出现在排序列表的开头,只要找到“X”就可以了。
如果必须在 X 之前出现至少一个“Y”才能进行有效匹配,则可以实施使用 takeWhile 的类似解决方案:
static Optional<Test> findFirstAfterAtLeastOne(String first, String all, List<Test> testList) {
testList.sort(Comparator.comparingInt(Test::getSortKey));
int index = (int) IntStream.range(0, testList.size())
.takeWhile(i -> all.equals(testList.get(i).getA()))
.count();
return index == 0
? Optional.empty()
: IntStream.range(index, testList.size())
.takeWhile(i -> first.equals(testList.get(i).getA()))
.mapToObj(testList::get)
.findFirst();
}
这里相同测试数据的输出是:
Optional.empty // no Y before X
Optional[Test{a='X', sortKey=20}]
Optional.empty
Optional.empty