Java Streams,只过滤第一个' N'火柴

时间:2018-03-28 06:08:36

标签: java

有没有办法只过滤第一个' n'匹配使用java流?

例如,如果我们有这个代码:

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

这将过滤所有&#34;一个&#34;字流中的字符串。

那么,如何过滤第一个&#39; n&#39;匹配并保持流的其余部分完好无损?

换句话说,如果n = 1那么,程序应该输出

"zero","two","three","four","five","one","one"

如果n = 2那么

&#34;零&#34;&#34; 2&#34;&#34;三&#34;&#34; 4&#34;&#34; 5&#34;&# 34;一个&#34;

3 个答案:

答案 0 :(得分:3)

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

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

然后用它来过滤

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

答案 1 :(得分:0)

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

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]

只要这个话题出现,这就是为什么无状态不仅在过滤器中而且在其他流方法中都很重要。

  • 用 1000 个“一个”、一个“两个”和另外 1000 个“一个”填充一个列表
  • 使用上述方法生成两个流,但同时过滤掉 100 个。
  • 然后比较两个结果列表。
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));

大小将相同,但列表并不总是相等。发生这种情况的唯一方法是在遇到“两个”之后删除一定数量的“一个”。由于限制是 first 100,这显然是一个问题。

答案 2 :(得分:-1)

这可能会帮助您完成检查

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