我对以流式方式从对象的有序列表中获得子列表感兴趣.子列表应该以匹配给定条件的对象开始,该对象与其属性之一有关,并且它应该以匹配不同条件的对象结束.
假设我有以下类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()过滤与给定缩写匹配的单个元素或元素列表.但是,我只是不知道如何找到一个以某个缩写开头,以另一个缩写结尾的子列表,因为介于两者之间的元素确实(并且应该)不符合条件,并且存在两个不同的条件.
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()));
}
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);