Reputation: 1763
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<Integer> isBig() {
return p -> p > 10;
}
public static void main(String args[]) {
List<Integer> list = new ArrayList<>();
Stream.generate(new Random()::nextInt)
.limit(100)
//???????
.forEach(a -> 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 < 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 -> list.add(a));
How can this be done?
Upvotes: 0
Views: 943
Reputation: 3498
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<Integer> list = Stream.generate(() -> r.nextInt())
.filter(n -> n > 0) // filter for positive numbers
.filter(n -> 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<Integer> list = Stream.generate(() -> 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.
Upvotes: 4
Reputation: 2252
Like this:
List<Integer> list = Stream.generate(new Random()::nextInt)
.filter(p -> p > 10)
.limit(100).collect(Collectors.toList());
Or like this one:
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());
}
}
Upvotes: 3