I think the most elegant way is to have a special collector.
I am pretty sure the only way you can guarantee that each item has an equal chance of being picked, is to collect, shuffle and re-stream. This can be easily done using built-in Collectors.collectingAndThen(...) helper.
Sorting by a random comparator or using randomized reducer, like suggested on some other answers, will result in very biased randomness.
List<String> wordList = sourceWords.stream()
.collect(Collectors.collectingAndThen(Collectors.toList(), collected -> {
Collections.shuffle(collected);
return collected.stream();
}))
.limit(listSize)
.collect(Collectors.toList());
You can move that shuffling collector to a helper function:
public class CollectorUtils {
public static <T> Collector<T, ?, Stream<T>> toShuffledStream() {
return Collectors.collectingAndThen(Collectors.toList(), collected -> {
Collections.shuffle(collected);
return collected.stream();
});
}
}
I assume that you are looking for a way to nicely integrate with other stream processing functions. So following straightforward solution is not what you are looking for :)
Collections.shuffle(wordList)
return wordList.subList(0, limitSize)
Stream
? Can't you shuffle the original list, and then return a copy withsubList
? – SynchroCollections.shuffle
andlist.subList(0,size)
should be enough. – Labialized