Java 8:如何比较集合的所有元素

2022-09-04 21:06:06

这可能是一个已经提出的问题,但我没有找到我需要的答案。

我有一个包含对象的集合,例如

public class MyObject {
    private LocalDate dateBeginning;
    private LocalDate dateEnd;

    public boolean overlap(MyObject otherDate) { /*code to check overlapping*/ }
}

我需要检查集合是否包含彼此重叠的元素。在“old-java”中,我会遍历集合两次,并检查是否存在所有组合,然后在找到它时中断或返回。

我们如何在Java 8中使用流和lambda来做到这一点?

我已经尝试过了,但似乎没有一个有效reduction()filter()

.filter((obj1, obj2) -> { if (obj1.overlap(obj2)) return true;}) //doesn't work

答案 1

正如您在问题中所说,一个可能的解决方案是循环使用集合两次,并确定是否存在任何重叠。因此,我们需要确定的是,对于集合中的任何元素,我们是否可以找到与之不同且重叠的任何其他元素。

因此,使用流 API,您可以获得以下功能:

boolean overlap = set.stream()
    .anyMatch(
        o1 -> set.stream().anyMatch(o2 -> o1 != o2 && o1.overlap(o2))
    );

anyMatch 将确定流的任何元素是否满足给定条件。因此,上面的代码询问是否存在一个与之不同的对象(我们可以在这里安全地使用,因为两个对象都来自同一个集合)并与之重叠。o1o2o1!=

请注意,这是一个 O(n²) 实现:集合被遍历两次。这在单个迭代中是可能的:在每次迭代中,保留间隔的并集;如果在任何时候当前区间和累积并集之间的交集是非空的,那么我们知道重叠已经命中。[dateBeginning, dateEnd]


答案 2

具有覆盖功能的想法的实现。如果您需要准确获取重叠范围或其编号,请使用此选项。compareTo

public class Range implements Comparable<Range> {
    private LocalDate startDate;
    private LocalDate endDate;

    public Range(LocalDate startDate, LocalDate endDate) {
        this.startDate = startDate;
        this.endDate = endDate;
    }

    @Override
    public int compareTo(Range range) {
        if (range.endDate.compareTo(endDate) >= 0 && range.startDate.compareTo(endDate) >= 0) return 1;
        if (range.endDate.compareTo(startDate) <= 0 && range.startDate.compareTo(startDate) <= 0) return -1;
        return 0;
    }
}

测试它:

LocalDate May1 = LocalDate.of(2016, 5, 1);
LocalDate May3 = LocalDate.of(2016, 5, 3);
LocalDate May5 = LocalDate.of(2016, 5, 5);
LocalDate May7 = LocalDate.of(2016, 5, 7);
LocalDate May9 = LocalDate.of(2016, 5, 9);

Set<Range> ranges = new HashSet<>();

ranges.add(new Range(May1, May5));
ranges.add(new Range(May3, May7));
ranges.add(new Range(May7, May9));

Set filteredRanges = ranges.stream().collect(Collectors.toCollection(TreeSet::new));
long totalOverlaps = ranges.size() - filteredRanges.size();
System.out.println(totalOverlaps + " overlapping range(s)"); 

请注意,范围 { } 被视为非重叠。要将此类情况(当一个范围等于另一个范围时)视为重叠,请将 , 替换为 ,。1..3, 3..5endDatestartDate<=>=<>


推荐