流式生成直到达到限制但仅匹配谓词的部分。

huangapple go评论80阅读模式
英文:

Stream generate until a limit but only matching a predicate

问题

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {
    // Your predicate
    public static Predicate<Integer> isBig() {
        return p -> p > 10;
    }

    public static void main(String args[]) {
        List<Integer> list = Stream.generate(new Random()::nextInt)
                .filter(isBig()) // Filter elements that match the predicate
                .limit(100)
                .collect(Collectors.toList());

        // Always needs to be 100
        System.out.println(list.size());
    }
}

Note: I've replaced .forEach(a -> list.add(a)) with .collect(Collectors.toList()) to directly collect the filtered and limited elements into a list. This is a more efficient and idiomatic way of using streams for this purpose.

英文:

How do I generate a list using Stream of exactly 100 elements. But all elements in the list should match a predicate.

Testcode:



import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Predicate;
import java.util.stream.Stream;


public class Main {
    // My predicate
    public static Predicate&lt;Integer&gt; isBig() {
        return p -&gt; p &gt; 10;
    }

    public static void main(String args[]) {
        List&lt;Integer&gt; list = new ArrayList&lt;&gt;();

        Stream.generate(new Random()::nextInt)
                .limit(100)
                //???????
                .forEach(a -&gt; list.add(a));

        // Always needs to be 100
        System.out.println(list.size());
    }
}

I could do this with a while loop and a counter (while counter &lt; 100). In the while loop I then would create random Integers, and only add the to a specific list and increase the counter when an element matches the predicate.

But this is not efficient and it needs to be done with streams.

PseudoCode:

 Stream.generate(new Random()::nextInt)
                .limit(100)
                .onlyAddIfMatches(isBig())
                .forEach(a -&gt; list.add(a));

How can this be done?

答案1

得分: 4

Edit:

在使用伪随机数源的流上不要使用filter方法,如果你可以以不同的方式实现你想要的功能。

如果你这样做,最好的情况是性能下降,最坏的情况是程序挂起。

这是因为如果你只是取随机数然后过滤它们,你很可能会生成比你实际需要的更多的数字。例如,如果你想要100个偶数随机数,平均而言你需要生成200个随机数。

最坏的情况是,如果伪随机数生成器(PRNG)有一个糟糕的种子,并且只循环生成不满足条件的数字,那么你永远无法收集到所需数量的数字。

总之:如果你需要n个满足特定条件(例如为正数)的随机数,则最好(如果可能)只创建n个随机数,并将不满足条件的映射为满足条件的(例如取负数的绝对值以仅获得正数)。

Original answer:

如果你想要过滤流,只需使用filter方法:
就像

Random r = new Random();
List<Integer> list = Stream.generate(() -> r.nextInt())
    .filter(n -> n > 0) // 过滤正数
    .filter(n -> n % 2 == 0) // 过滤偶数
    .limit(10)
    .collect(Collectors.toList());

但是你应该注意你的流源。如果你使用伪随机数生成器(PRNG),你应该尝试限制生成的数字范围。

例如,上面的例子可以这样实现

Random r = new Random();
List<Integer> list = Stream.generate(() -> r.nextInt(Integer.MAX_VALUE/2) * 2)
    .limit(10)
    .collect(Collectors.toList());

并且应该更受欢迎,因为第一个例子可能会遇到永远不满足要求的伪随机数循环。

所以作为一个通用的规则。如果你处理一个随机源,请尝试从输入中创建你想要的数字,而不是过滤随机输入。

英文:

Edit:

Do not use the filter method on a stream with a pseudo-random-number source if you can do what ever you want to do differently.

If you do you will at best run into performance drops and at worst into a hanging program.

This is because if you just take random numbers and filter them you will most probably gennerate more numbers than you need.
For example if you want 100 even random numbers you will on average need to generate 200 random numbers.

The worst case comes into play if the PRNG has a bad seed and cycles only through numbers that does not match the predicate, so you can never collect the requiered amount of numbers.

To conclude: If you need n random numbers that meet a certain predicate (for example positive) the (if possible) just create n random numbers and map the ones that do not match the predicate to one that matches (for example take the absolute value of the negative numbers to only have positive numbers).

Original answer

If you want to filter a stream just use the method filter:
like

Random r = new Random();
List&lt;Integer&gt; list = Stream.generate(() -&gt; r.nextInt())
    .filter(n -&gt; n &gt; 0) // filter for positive numbers
    .filter(n -&gt; n % 2 == 0) // filter for even
    .limit(10)
    .collect(Collectors.toList());

But you should be cousious about your stream source. If you use a PRNG you should try to limit the range of numbers that are generated.

For example the above example can be achived with

Random r = new Random();
List&lt;Integer&gt; list = Stream.generate(() -&gt; r.nextInt(Integer.MAX_VALUE/2) * 2)
    .limit(10)
    .collect(Collectors.toList());

and is to be preferred, because the first example could run into a cycle of pseudo-random-numbers that never meet the requirements.

So as a general rule. If you deal with a random source, try to create from the input the numbers you want and not filter the random input.

答案2

得分: 3

像这样:

List<Integer> list = Stream.generate(new Random()::nextInt)
                    .filter(p -> p > 10)
                    .limit(100).collect(Collectors.toList());

或者像这样:

public class Main {
    
    private static boolean isBig(Integer input) {
        return input > 10;
    }
    
    public static void main(String args[]) {
        List<Integer> list = Stream.generate(new Random()::nextInt)
                    .filter(Main::isBig)
                    .limit(100).collect(Collectors.toList());
    }
}
英文:

Like this:

List&lt;Integer&gt; list = Stream.generate(new Random()::nextInt)
                .filter(p -&gt; p &gt; 10)
                .limit(100).collect(Collectors.toList());

Or like this one:

public class Main {

    private static boolean isBig(Integer input) {
        return input &gt; 10;
    }

    public static void main(String args[]) {
        List&lt;Integer&gt; list = Stream.generate(new Random()::nextInt)
                .filter(Main::isBig)
                .limit(100).collect(Collectors.toList());
    }
}

huangapple
  • 本文由 发表于 2020年7月27日 21:02:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/63115915.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定