如何通过Java stream API获取以某个匹配开始并以另一个匹配结束的子列表?
我对如何通过Java stream API获取以某个匹配开始并以另一个匹配结束的子列表?,java,java-8,java-stream,Java,Java 8,Java Stream,我对流y方法感兴趣,该方法可以从有序的对象列表中获取子列表。子列表应以一个对象开始,该对象匹配与其属性之一相关的给定条件,并应以一个对象结束,该对象匹配不同的条件 比方说,我有以下类元素: import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; public class Element implements Comparable<Element> { String abbrevi
流
y方法感兴趣,该方法可以从有序的对象列表中获取子列表。子列表应以一个对象开始,该对象匹配与其属性之一相关的给定条件,并应以一个对象结束,该对象匹配不同的条件
比方说,我有以下类元素
:
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) + "]";
}
}
我需要从(包括)“MNO”
到(包括)“YZ1”
的子列表,保持它在源代码列表中的顺序,将创建时间
放在一边
我知道如何在不使用流的情况下做到这一点(比如查找开始和结束的索引,然后从索引开始
到索引结束
),这可能已经足够了,但在某种程度上是过时的,并不能真正满足我使用现代API的欲望
我可以添加使其工作的方法,但它们只是描述问题的另一种形式,而我无法使用单个stream语句来解决这个问题。此外,这些方法在一系列不同的问题中进行了解释,这些问题提出了一种普遍的可能性,而不是针对流API
一般情况下:有两个条件和一个
列表
,其中一个子列表将被收集,其第一个元素是一个匹配条件1,其最后一个元素是一个匹配条件2,同时这些元素之间的所有元素也被收集,并且顺序保持原样
因此,如果您知道使用单流API语句获得所需子列表的可能性,请将其添加为答案。
同时,我将看看reduce()
方法,也许这就是谜团的答案
编辑我找到了一个解决方案,它使用
stream()
调用为我提供了所需的结果,但我需要其中的三个。一个获取与第一个条件匹配的元素,第二个获取与第二个条件匹配的元素,然后一个使用前两个流()中找到的两个元素的creationTime
s获取所需子列表:
publicstaticvoidmain(字符串[]args){
列表元素=生成满足元素();
//打印原点一次,后跟人眼的水平分隔符
element.forEach(element->System.out.println(element.toString());
System.out.println(“-------------------------------------”);
//找到应该是所需对象的第一个元素的引用对象
//子列表
Element fromInclude=elements.stream()
.filter(element->element.get缩写().equals(“MNO”)).findFirst()
.get();
Element toIncluding=elements.stream()
.filter(element->element.get缩写().equals(“YZ1”)).findFirst()
.get();
List mnoToYz1=elements.stream()
.过滤器(滤芯->
(element.getCreationTime().isAfter(fromInclude.getCreationTime())
&&元素.getCreationTime().isBefore(包括.getCreationTime())
||元素.getCreationTime().isEqual(fromInclude.getCreationTime())
||元素.getCreationTime().isEqual(包括.getCreationTime())
.collect(Collectors.toList());
mnoToYz1.forEach(element->System.out.println(element.toString());
}
看起来您需要流上的takeWhile
/dropWhile
方法。查看库by如果输入列表是有序的,获取子列表的另一种方法是使用范围,而不是示例中的对象比较,如下所示:
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);
int fromcluding=IntStream.range(0,elements.size())
.filter(i->elements.get(i).get缩写().equals(“MNO”))
.findFirst().orElse(0);
int-toIncluding=IntStream.range(fromcluding,elements.size())
.filter(i->elements.get(i).get缩写().equals(“YZ1”))
.findFirst().orElse(elements.size()-1);
列表mnoToYz1=元素。子列表(从包含到包含+1);
感谢您建议使用该库,但我真的不想包含比现有库更多的外部库。不管怎样,这是一个有用的答案,可能会在未来的项目中对我有所帮助。@deaartakeWhile
和dropWhile
操作是在Java 9中添加到streams中的。疑问:你真的为过滤时的缩写设置或creationTime
持续时间而烦恼吗?我的意思是,如果我简单地将其表述为List mnotoyz1ss=elements.stream().takeWhile(element->element.getCreationTime().compareTo(fromIncluding)>=0.dropWhile(element->element.getCreationTime().compareTo(toIncluding)@nullpointer我不能/不想使用takeWhile
方法,这就是为什么它不能解决我的问题。我找到了一种使用creationTime
的方法,并在中编辑了该方法,但问题仍然是如何使用缩写
并在流之前不提取这两个元素。我认为使用命令式方法解决它的方法还需要至少两个while
循环。因此,您当前的解决方案也没有任何问题。除了|
条件在检查特定的持续时间时看起来不太确定之外。@nullpointer好的,我也这么认为。我可能会自己回答这个问题,我想f我发现了一种可能性。但请记住,这不会像在样本中那样执行持续时间检查。根据我的理解,根据您的问题,这也不是必需的。第二个流可能使用IntStream.range(fromInclude,elements.size())
。最好的答案是接受的,尽管需要的流比其他流多
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);