【问题标题】:Collect the largest successive sequence integers in a list using streams使用流收集列表中最大的连续序列整数
【发布时间】:2016-02-23 08:16:05
【问题描述】:

我有一个整数值列表,我想在列表中找到最大的连续序列整数。

例如,令 L 为以下整数列表:

L = {1, 3, 4, 6, 7, 8, 10, 12, 13}

然后我只想从流中收集以下整数:

6、7、8

因为这些数字是列表 L 中最大的连续序列整数。

是否可以在 Java 8 中使用流来做到这一点?

这是我目前在 Java 中使用简单迭代的结果:

    int maxSeqSize = 0;
    List<Cards> maxSeq;
    int currentNumber;
    int startSeq = -1;

    List<Card> currentCards = new ArrayList<> Cards.getCards());
    Collections.sort(currentCards, Cards::CompareByNumber);

    for (currentNumber = 0; currentNumber< Cards.getCards().size() - 1; currentNumber++){
           if((isSequentialCards(Cards.getCards().get(currentNumber ),
                                Cards.getCards().get(currentNumber + 1)))) {
            if (startSeq == -1) 
               startSeq = currentNumber ;

           }
           else {
             if(startSeq > 0 && currentNumber - startSeq + 1 >= maxSeqSize ) 
             {                                        
                  maxSeqSize = currentNumber - startSeq + 1;
                  maxSeq = currentCards .subList(startSeq,currentNumber +1);
             }
                    startSeq = -1;
           }
      }

      return maxSeq;

虽然 isSequentialCards 通过值比较两张卡:

private boolean isSequentialCards(Card c1, Card c2) {
    if((c1.getNumber() == c2.getNumber() - 1))
        return true;
    return false;
}

提前致谢

【问题讨论】:

  • 你有没有尝试过或者你希望有人能给你一个解决方案?
  • 流对于此类问题是一个糟糕的选择。您正在寻找迭代列表,并为每个元素开始另一个迭代,以查看您拥有连续元素的距离。带有整数索引的 for 循环似乎更自然
  • 这并不难。您只需对列表进行排序(如果未排序),迭代(检查位置i+1 中的元素是否等于位置i + 1
  • 这是一个使用我的 StreamEx 库的单线器:StreamEx.of(1, 3, 4, 6, 7, 8, 10, 12, 13).groupRuns((a, b) -&gt; b-a == 1).maxBy(List::size).orElse(Collections.emptyList())
  • 查看这个gist 使用collect() 获得两个答案。如果这个问题没有(不公平地)关闭,我会回答。

标签: java java-8 java-stream


【解决方案1】:

我能用流做的最好的事情:

List<Card> largestSequence = cards.stream()
            //.sorted((card1, card2) -> card1.getNumber() - card2.getNumber())
            .collect(
                    (Supplier<List<List<Card>>>) ArrayList::new,
                    (sequences, currentCard) -> {
                        if (sequences.size() == 0 || !isSequentialCards(getLast(getLast(sequences)), currentCard)) {
                            sequences.add(new ArrayList<>());
                        }
                        getLast(sequences).add(currentCard);
                    },
                    List::addAll)
            .stream()
            .sorted((sequence1, sequence2) -> sequence2.size() - sequence1.size())
            .findFirst()
            .get();

步骤是什么:

  • 查找所有连续数字的序列
  • 从大到小排序
  • 获取第一个序列(最大)

如何?

  • sorted :我对此发表了评论,因为我不知道您是否想要列表顺序中的最大序列,还是按照@cr0ss 的建议。它基本上按升序对列表进行排序,从小到大。
  • collect :您可以在其中看到 Collectors 可以提供的三个“操作”(如 Collectors.toList)。这就是找到一系列连续数字的所有魔力发生的地方。此实现尝试收集连续数字的序列列表(也是列表)。 :
    • supplier:初始化容器:卡片列表(卡片序列列表)。
    • accumulator : 是什么让一个数字被插入到一个序列中(在下一部分中描述)。
    • combiner : 定义如何合并两个列表。没用但需要,基本的addAll就够了。
  • sorted : 从大到小排序
  • findFirst :取第一个,因此最大

我在another answer 中找到了有关收藏家的信息。其余全部来自 java 文档。

是什么让数字成为序列的一部分?

给定一个列表 3、4、6 不存在序列,创建一个新序列。

[] -> [[]]

在最后一个序列的末尾插入 3。

[[]] -> [[3]]

至少存在一个序列,并且 4 与最后一个序列的最后一个数字 3 连续。 在最后一个序列的末尾插入 4。

[[3]] -> [[3, 4]]

存在一个序列,但 6 与最后一个序列的最后一个数字 4 不连续。创建一个新序列。

[[3, 4]] -> [[3, 4], []]

在最后一个序列的末尾插入 6。

[[3, 4], []] -> [[3, 4], [6]]

就像@Manos 所说,流是解决这个问题的一个奇怪的选择。我认为问题在于,当您不习惯于流、lambda 或收集器时,它可能很难维护,尤其是像这里这样的 one-liner (个人选择,我更喜欢我的代码是可维护的任何人)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    相关资源
    最近更新 更多