繁体   English   中英

使用java 8流在已排序的数字列表中查找最长的连续数字

[英]Find longest consecutive numbers in a list of sorted numbers using java 8 stream

我有一段使用传统for循环编写的代码,如下所示。 我想重构它以使用java 8流并删除for循环。 以下代码的输出应为3,因为这是最长的连续数字列表(4,5和6)

    List<Integer> weekDays = Lists.newArrayList(1, 2, 4, 5, 6);

    List<Integer> consecutiveIntervals = Lists.newArrayList();
    int maxConsecutiveTillNow = 1;
    for (int i = 1; i < weekDays.size(); i++) {
        if (weekDays.get(i) - weekDays.get(i - 1) == 1) {
            maxConsecutiveTillNow++;
        } else {
            consecutiveIntervals.add(maxConsecutiveTillNow);
            maxConsecutiveTillNow = 1;
        }
    }
    consecutiveIntervals.add(maxConsecutiveTillNow);

    System.out.println(consecutiveIntervals.stream()
                                           .max(Integer::compareTo)
                                           .get()
                      );

Stream API不太适合这类问题。 几乎不可能以正确的方式跟踪Stream中看到的元素。 所以你必须去多个Streams

根据斯图尔特马克斯的答案之一。

List<Integer> weekDays = Arrays.asList(1, 2, 4, 5, 6);
int[] indices = IntStream.rangeClosed(0, weekDays.size())
   .filter(i -> i == 0 || i == weekDays.size() || weekDays.get(i - 1) + 1 != weekDays.get(i))
   .toArray();
int longest = IntStream.range(0, indices.length - 1).map(i -> indices[i + 1] - indices[i])
   .max().orElseThrow(NoSuchElementException::new);
System.out.println(longest);

产量

3

那么流的思想是彼此独立地处理流中的项目。 该模式的最大好处是您可以并行执行,因为流API的设计是并发的(即,您不应该在流的顺序项的处理之间保持状态)。 在您的特定任务中,数组的使用是最合适的。

创建序列列表并将其排序为所有序列列表中的最长序列。

例如,如果有一个List [1,2,4,5,6] ,它分为:

[[1,2],[4,5,6]]

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;

public class NumberSequence {
    public static void main(String[] args) {
        List<Integer> weekDays = Arrays.asList(1, 2, 4, 5, 6);

        List<List<Integer>> allWeekdaySequences = weekDays.stream()
                                                          .collect(
                                                                    (Supplier<List<List<Integer>>>) ArrayList::new,
                                                                    (sequences, currentElement) -> generateCombinedBatchesFor(sequences, currentElement),
                                                                    List::addAll);

        System.out.println(allWeekdaySequences);

        Optional<List<Integer>> longestSequence = allWeekdaySequences.stream()
                                                           .sorted((seq1, seq2) -> seq2.size() - seq1.size())
                                                           .findFirst();

        System.out.println(longestSequence.isPresent() ? longestSequence.get().size() : "Nothing found!!");
    }

    private static void generateCombinedBatchesFor(List<List<Integer>> sequences, Integer currentElement) {
        if (needsNewSequence(sequences, currentElement)) {
            sequences.add(new ArrayList<>());
        }
        getLastSequence(sequences).add(currentElement);
    }

    private static boolean needsNewSequence(List<List<Integer>> sequences, Integer currentElement) {
        return sequences.size() == 0 || !isConsecutiveDay(getLastElement(getLastSequence(sequences)),
                currentElement);
    }

    private static boolean isConsecutiveDay(Integer lastElement, Integer currentElement) {
        return currentElement - lastElement == 1;
    }

    private static Integer getLastElement(List<Integer> lastSequence) {
        return !lastSequence.isEmpty() ? lastSequence.get(lastSequence.size()-1) : -1;
    }

    private static List<Integer> getLastSequence(List<List<Integer>> sequences) {
        return sequences.get(sequences.size()-1);
    }
}

产量

3

为此,您需要部分缩减(批处理),java 8流API不提供。

你可以通过分裂器(类似于这个答案 )自己实现它,或者使用提供它的库,例如streamex或proton-pack

如果你不介意使用第三方库,我可能会推荐我的免费StreamEx库,它增强了标准的Stream API,并且除其他外,还为运营商提供了部分减少:

StreamEx.of(weekDays)
        .collapse((a, b) -> b - a == 1, Collectors.counting())
        .max(Comparator.naturalOrder())

这里崩溃是一个部分减少算子。 第一个BiPredicate告诉给定的相邻元素对是否应该一起还原或新的还原组应该开始。 这里的规则是相邻元素应该相差1.第二个参数是用于执行缩减的收集器(这里简单地counting()收集器)。 因此,在collapse后,我们有组长度流(输入为2和3)。 最后我们使用标准的max()运算符。

StreamEx库与Stream API完全兼容(StreamEx创建的Stream可以用作普通流)。 collapse算子是懒惰的,非常快速且并行友好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM