从包含满足流条件的第 n 个元素的 Java 列表中获取子列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32309863/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 20:00:20  来源:igfitidea点击:

Getting sublist from a Java list with nth elements that fulfills a condition with streams

javalambdafunctional-programmingjava-8java-stream

提问by user3483969

I have a very simple use case

我有一个非常简单的用例

Given a list of letters with A and Bs, I want to get the sublist that contains the first N Bs, for example:

给定带有 A 和 B 的字母列表,我想获取包含前 N 个 B 的子列表,例如:

  • f(3, [A A A B A B A B A A]) = [A A A B A B A B]
  • f(2, [A A A B A B A B A A]) = [A A A B A B]
  • f(1, [A A B A B A]) = [A A B]
  • f(0, [A A B A B]) = []
  • f(3, [AAABABABA]) = [AAABABAB]
  • f(2, [AAABABABA]) = [AAABAB]
  • f(1, [AABABA]) = [AAB]
  • f(0, [AABAB]) = []

By following an imperative approach, this is relatively easy, count until we find N Bs, and then get the sublist until that position.

通过遵循命令式方法,这相对容易,计数直到我们找到 N 个 B,然后获取直到该位置的子列表。

However, I couldn't find any functional solution with lambdas, since the operation on every node seems to be independent from the others (which I guess make sense for parallelization).

但是,我找不到 lambda 的任何功能解决方案,因为每个节点上的操作似乎都独立于其他节点(我认为这对并行化很有意义)。

采纳答案by Tagir Valeev

If your input is a Listwith fast random access, you can solve your problem using the stream of indices:

如果您的输入是List具有快速随机访问的,您可以使用索引流解决您的问题:

public static List<String> f(int n, List<String> input) {
    int fence = IntStream.range(0, input.size())
                         .filter(idx -> input.get(idx).equals("B")) // leave only B's
                         .skip(n-1)
                         .findFirst() // an index of n-th B
                         .getAsInt(); // with throw NoSuchElementException if not enough B's
    return input.subList(0, fence+1);
}

Usage example:

用法示例:

System.out.println(f(3, Arrays.asList("A", "A", "A", "B", "A", "B", "A", "B", "A", "A")));
System.out.println(f(2, Arrays.asList("A", "A", "A", "B", "A", "B", "A", "B", "A", "A")));
System.out.println(f(1, Arrays.asList("A", "A", "A", "B", "A", "B", "A", "B", "A", "A")));

However despite I love Stream API I would solve this problem imperatively.

然而,尽管我喜欢 Stream API,但我还是会迫切地解决这个问题。

回答by Karol Król

This code snippet do the job.

这段代码片段完成了这项工作。

public static void main(String[] args) {
    final String input = "A A A B A B A B A A";
    final String[] array = input.split(" ");
    final List<String> list = Arrays.asList(array);
    final List<String> result = getSubList(list, 3);
    System.out.println("Result=" + result);
}

public static List<String> getSubList(final List<String> list, final int limit) {
    final AtomicInteger counter = new AtomicInteger();
    return list.stream()
            .filter(ch -> {
                if (ch.equals("B") && counter.incrementAndGet() == limit) return true;
                return counter.get() < limit;
            })
            .collect(Collectors.toList());
}

回答by user_3380739

Here is code by AbacusUtil

这是AbacusUtil 的代码

List<String> input = N.asList("A", "A", "A", "B", "A", "B", "A", "B", "A", "A");
List<String> list = Stream.of(input).takeWhile(MutableInt.of(3), (e, cnt) -> cnt.getAndAdd(e.equals("B") ? -1 : 0) > 0).toList();
N.println(list);

Declaration: I'm the developer of AbacusUtil.

声明: 我是AbacusUtil的开发者。