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

从Java列表中获取满足流条件的第n个元素的子列表,java,lambda,functional-programming,java-8,java-stream,Java,Lambda,Functional Programming,Java 8,Java Stream,我有一个非常简单的用例 给定带有a和b的字母列表,我想得到包含前N个b的子列表,例如: f(3,[A B A B A A A B A])=[A A B A B B B] f(2,[A B A B A B A])=[A A B A B] f(1[A B A B A])=[A B] f(0[ab])=[] 通过遵循命令式方法,这是相对容易的,计数直到找到N个B,然后得到子列表直到该位置 但是,我找不到任何使用lambdas的功能解决方案,因为每个节点上的操作似乎都独立于其他节点(我想这对于并行化

我有一个非常简单的用例

给定带有a和b的字母列表,我想得到包含前N个b的子列表,例如:

  • f(3,[A B A B A A A B A])=[A A B A B B B]
  • f(2,[A B A B A B A])=[A A B A B]
  • f(1[A B A B A])=[A B]
  • f(0[ab])=[]
通过遵循命令式方法,这是相对容易的,计数直到找到N个B,然后得到子列表直到该位置


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

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

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);
}

然而,尽管我喜欢流API,但我还是必须解决这个问题。

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

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());
}
publicstaticvoidmain(字符串[]args){
最终字符串输入=“A B A B A”;
最终字符串[]数组=input.split(“”);
最终列表=Arrays.asList(array);
最终列表结果=getSubList(列表,3);
System.out.println(“结果=”+结果);
}
公共静态列表getSubList(最终列表,最终整数限制){
最终AtomicInteger计数器=新的AtomicInteger();
return list.stream()
.过滤器(ch->{
如果(ch.equals(“B”)&&counter.incrementAndGet()==limit)返回true;
返回计数器。get()
这里是代码编写者

List input=N.asList(“A”、“A”、“A”、“B”、“A”、“B”、“A”、“A”、“A”);
List List=Stream.of(input).takeWhile(MutableInt.of(3),(e,cnt)->cnt.getandad(e.equals(“B”)?-1:0)>0.toList();
N.println(列表);

声明:我是AbacusUtil的开发者。

你说的lambdas功能解决方案是什么意思?你是说溪流吗?你能给我们一些伪代码让我们知道你想要的是什么吗?我只想要使用streams的代码,它可以执行以下命令函数:
private List getSubList(int maxamunt,List inputList){ArrayList result=new arrararylist();int itemsfund=0;for(String item:inputList){result.add(item);if(item.equals(“B”))itemsFound++;if(itemsFound==maxAmount);break;}返回结果;}
等待Java 9和
流#takeWhile
。但是你的逻辑需要一个有状态谓词,这永远是一个绊脚石。谢谢Tagir,这正是我想要的。无论如何,我必须同意你的看法,在这种情况下,命令式方法似乎更具解释性,因此我将在代码中保留它,就像现在一样,您的帮助对于深入理解该语言的功能非常有价值。请注意,您的解决方案违反了
filter
method:提供的谓词必须是无状态的。@TagirValeev不是“必须”而是“应该”。这个解决方案没有打破任何限制。对AtomicInteger使用的操作是同步的(和原子的)。无论如何,在这种情况下,除了使用一个线程的简单流之外,没有使用parallelStream的选项。不要这么正统——Java 8这不是真正的函数式编程语言。@KarolKról感谢您的选择。即使不能确定它是否违反了过滤器的约定,我也觉得它有点复杂(即应该使用原子整数而不是常规整数)。最后,我认为,在这方面,当务之急的做法更为明确case@user3483969我同意你的看法,但如果你把IMO Java流API与类似的Scala API相比,它就差了。此外,TagirValeev方法也不是“必要的”,因为它读取/比较可变集合的元素:/事实上更糟糕,因为列表上的get方法不是原子的-我只是为我的超级解决方案辩护:P投票人;)@KarolKról Yep,虽然我喜欢编写更多“功能性”风格的代码,但API并不像Scala那样灵活。
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());
}
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);