如何通过Java流API获取以特定匹配开始并以不同匹配结束的子列表?
作者:互联网
我对以流式方式从对象的有序列表中获得子列表感兴趣.子列表应该以匹配给定条件的对象开始,该对象与其属性之一有关,并且它应该以匹配不同条件的对象结束.
假设我有以下类Element:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Element implements Comparable<Element> {
String abbreviation;
LocalDateTime creationTime;
public Element(String abbreviation, LocalDateTime creationTime) {
this.abbreviation = abbreviation;
this.creationTime = creationTime;
}
public String getAbbreviation() {
return abbreviation;
}
public void setAbbreviation(String abbreviation) {
this.abbreviation = abbreviation;
}
public LocalDateTime getCreationTime() {
return creationTime;
}
public void setCreationTime(LocalDateTime creationTime) {
this.creationTime = creationTime;
}
@Override
public int compareTo(Element otherElement) {
return this.creationTime.compareTo(otherElement.getCreationTime());
}
@Override
public String toString() {
return "[" + abbreviation + ", "
+ creationTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + "]";
}
}
我收到一个List< Element>由creationTime排序.现在,我想找出两个特定元素之间是否只有它们的缩写.我知道如何使用findFirst()或findAny()和Collectors.toList()过滤与给定缩写匹配的单个元素或元素列表.但是,我只是不知道如何找到一个以某个缩写开头,以另一个缩写结尾的子列表,因为介于两者之间的元素确实(并且应该)不符合条件,并且存在两个不同的条件.
假设我具有以下List< Element>(生成方法):
private static List<Element> generateSomeElements() {
List<Element> elements = new ArrayList<Element>();
LocalDateTime now = LocalDateTime.now();
Element elementOne = new Element("ABC", now.minus(14, ChronoUnit.DAYS));
Element elementTwo = new Element("DEF", now.minus(13, ChronoUnit.DAYS));
Element elementThree = new Element("GHI", now.minus(12, ChronoUnit.DAYS));
Element elementFour = new Element("JKL", now.minus(11, ChronoUnit.DAYS));
Element elementFive = new Element("MNO", now.minus(10, ChronoUnit.DAYS));
Element elementSix = new Element("PQR", now.minus(9, ChronoUnit.DAYS));
Element elementSeven = new Element("STU", now.minus(8, ChronoUnit.DAYS));
Element elementEight = new Element("VWX", now.minus(7, ChronoUnit.DAYS));
Element elementNine = new Element("YZ1", now.minus(6, ChronoUnit.DAYS));
Element elementTen = new Element("234", now.minus(5, ChronoUnit.DAYS));
elements.add(elementOne);
elements.add(elementTwo);
elements.add(elementThree);
elements.add(elementFour);
elements.add(elementFive);
elements.add(elementSix);
elements.add(elementSeven);
elements.add(elementEight);
elements.add(elementNine);
elements.add(elementTen);
return elements;
}
我需要从(包括)“ MNO”到(包括)“ YZ1”的子列表,保持其在源列表中的顺序,不考虑creationTime.
我知道如何在不使用流的情况下做到这一点(例如查找开始和结束的索引,然后从索引开始到索引结束获取元素),这也许足够了,但是有点过时了,不能真正满足我对使用现代API的贪婪.
我可以添加使其工作的方式,但是它们只是描述问题的另一种形式,我无法使用单个流语句解决该问题.另外,这些方法在许多不同的问题中进行了解释,这些问题要求普遍的可能性,而不是针对流API.
In general:
There are two conditions and aList<Element>
where a sublist is to be collected whose first element is the one matching condition 1 and whose last element it the one matching condition 2 while all elements between those are collected, too, and the order stays as it is in the origin.
因此,如果您知道可以通过单个流API语句获取所需的子列表,请添加它作为答案.
同时,我将看看reduce()方法,也许这就是谜底的答案了……
编辑
我找到了一个解决方案,该解决方案使用stream()调用可以为我提供所需的结果,但是我需要三个.一个会获取与第一个条件匹配的元素,第二个会找到与第二个条件匹配的元素,然后一个会使用在前两个stream()中找到的两个元素的creationTimes来获取所需的子列表:
public static void main(String[] args) {
List<Element> elements = generateSomeElements();
// print origin once followed by a horizontal separator for the human eye
elements.forEach(element -> System.out.println(element.toString()));
System.out.println("————————————————————————————————");
// find the reference object which should be the first element of the desired
// sublist
Element fromIncluding = elements.stream()
.filter(element -> element.getAbbreviation().equals("MNO")).findFirst()
.get();
Element toIncluding = elements.stream()
.filter(element -> element.getAbbreviation().equals("YZ1")).findFirst()
.get();
List<Element> mnoToYz1 = elements.stream()
.filter(element ->
(element.getCreationTime().isAfter(fromIncluding.getCreationTime())
&& element.getCreationTime().isBefore(toIncluding.getCreationTime()))
|| element.getCreationTime().isEqual(fromIncluding.getCreationTime())
|| element.getCreationTime().isEqual(toIncluding.getCreationTime()))
.collect(Collectors.toList());
mnoToYz1.forEach(element -> System.out.println(element.toString()));
}
解决方法:
如果输入列表是有序的,则获取subList的另一种方法是使用范围而不是示例中的对象比较:
int fromIncluding = IntStream.range(0, elements.size())
.filter(i -> elements.get(i).getAbbreviation().equals("MNO"))
.findFirst().orElse(0);
int toIncluding = IntStream.range(fromIncluding, elements.size())
.filter(i -> elements.get(i).getAbbreviation().equals("YZ1"))
.findFirst().orElse(elements.size() - 1);
List<Element> mnoToYz1 = elements.subList(fromIncluding, toIncluding+1);
标签:java-8,java-stream,java 来源: https://codeday.me/bug/20191211/2106434.html