编程语言
首页 > 编程语言> > 如何通过Java流API获取以特定匹配开始并以不同匹配结束的子列表?

如何通过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 a List<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