Java流,仅过滤第一个';N';比赛

Java流,仅过滤第一个';N';比赛,java,Java,是否有任何方法可以使用java流仅过滤前“n”个匹配项 例如,如果我们有以下代码: List<String> words = Arrays.asList("zero","one","two","three","four","five","one","one"); List<String> filteredWords = words.stream() .filter(word->!word.equals("one"))//filter

是否有任何方法可以使用java流仅过滤前“n”个匹配项

例如,如果我们有以下代码:

List<String> words = Arrays.asList("zero","one","two","three","four","five","one","one");

List<String> filteredWords = words.stream()
                .filter(word->!word.equals("one"))//filter all "one" strings..
                .collect(Collectors.toList());

System.out.println(filteredWords);
如果n=2,则


“零”、“二”、“三”、“四”、“五”、“一”

您可以创建一个类来进行过滤

class LimitedFilter<T> implements Predicate<T> {
    int matches = 0;
    final int limit;
    private Predicate<T> delegate;
    public LimitedFilter<T>(Predicate<T> p, int limit) { 
        delegate = p; this.limit = limit;
    }
    public boolean test(T toTest) {
        if (matches > limit) return true;
        boolean result = delegate.test(toTest);
        if (result) matches++;
        return result;
    }
}
类LimitedFilter实现谓词{
int匹配=0;
最终整数限制;
私有谓词委托;
public LimitedFilter(谓词p,int limit){
委托=p;this.limit=limit;
}
公共布尔测试(T-toTest){
如果(匹配>限制)返回true;
布尔结果=委托测试(toTest);
如果(结果)匹配++;
返回结果;
}
}
然后用它来过滤

Predicate<String> limited = new LimitedFilter<>(w -> !"one".equals(w), 5);
List<String> filteredWords = words.stream()
            .filter(limited) //filter first five "one" strings..
            .collect(Collectors.toList());
Predicate limited=new LimitedFilter(w->!“一”。等于(w),5);
List filteredWords=words.stream()
.filter(limited)//筛选前五个“一”字符串。。
.collect(Collectors.toList());

这可能有助于您查看全文

 List<String> 
words = Arrays.asList("zero","one","two","three","four","five","one","one");

    Stream<String> sortedList =  words.stream().filter(word -> 
     word.contains("n"));

    sortedList.forEach(str->System.out.println(str));
列表
单词=数组。asList(“零”、“一”、“二”、“三”、“四”、“五”、“一”、“一”);
Stream sortedList=words.Stream().filter(word->
字。包含(“n”);
sortedList.forEach(str->System.out.println(str));

你可以这样做。但正如已经警告的那样,谓词应该是无状态的。同时运行这个程序会有问题。尽管流很流行,但仅仅因为您可以使用它们来执行任务并不总是意味着您应该这样做

List<String> words = Arrays.asList("zero","one","two","three","four","five","one","one");
AtomicInteger count = new AtomicInteger(0);
int limit = 1;
List<String> filteredWords = words.stream()
                .filter(word->!(word.equals("one") && count.incrementAndGet() <= limit))
                .collect(Collectors.toList());

System.out.println(filteredWords);
只要这个话题一提出来,下面就是为什么无状态不仅在过滤器中很重要,而且在其他流方法中也很重要

  • 用1000个“一”,一个“二”,再加上1000个“一”
  • 使用上述方法生成两个并行流,过滤掉100个流
  • 然后比较两个结果列表
List wordList=Stream.generate(()->“一”).limit(1000)
.collect(收集器.toCollection(ArrayList::new));
添加(“两个”);
addAll(Stream.generate(()->“一”).limit(1000.toList());
AtomicInteger计数=新的AtomicInteger(0);
整数极限=100;
List result1=wordList.parallelStream()
.filter(word->!(word.equals(“一”)
&&count.incrementAndGet()!(word.equals(“一”)

&&count.incrementAndGet()否,因为流谓词应该是无状态的。只需调用
remove(“one”)
n次即可(在可变列表上)。否,流谓词应该是无状态的。@shmosel是的,但它们不必是:"还请注意,试图从行为参数访问可变状态在安全性和性能方面给您带来了一个错误的选择;如果您不同步对该状态的访问,您将面临数据竞争,因此您的代码将被破坏,但如果您同步对该状态的访问,您将面临竞争破坏并行性的风险您希望从“-”中获益的ism。OP在我的回答中确实需要小心使用这种方法,但他可以。的文档说它需要一个“无状态谓词”。我认为您的引用更具说明性。@shmosel我发布的引用来自您发布的筛选文档中指向“无状态”条件的链接:)我认为我们同意这样做不是最好的主意。可能最好创建一个自定义的
收集器
或其他东西,但这会隐藏过滤的复杂性。如何只过滤出“一”的前n个实例?
List<String> words = Arrays.asList("zero","one","two","three","four","five","one","one");
AtomicInteger count = new AtomicInteger(0);
int limit = 1;
List<String> filteredWords = words.stream()
                .filter(word->!(word.equals("one") && count.incrementAndGet() <= limit))
                .collect(Collectors.toList());

System.out.println(filteredWords);
[zero, two, three, four, five, one, one]
List<String> wordList = Stream.generate(()->"one").limit(1000)
        .collect(Collectors.toCollection(ArrayList::new));
wordList.add("two");
wordList.addAll(Stream.generate(()->"one").limit(1000).toList());

AtomicInteger count = new AtomicInteger(0);
int limit = 100;
List<String> result1 = wordList.parallelStream()
        .filter(word -> !(word.equals("one")
                && count.incrementAndGet() <= limit))
        .collect(Collectors.toList());

count.set(0);
List<String> result2 = wordList.parallelStream()
        .filter(word -> !(word.equals("one")
                && count.incrementAndGet() <= limit))
        .collect(Collectors.toList());
System.out.println(result1.size());
System.out.println(result2.size());
System.out.println(result1.equals(result2));