如何从流中获取随机对象

Adr*_*ebs 20 java java-8 java-stream

假设我有一个单词列表,我想创建一个方法,将新列表的大小作为参数并返回新列表.如何从原始sourceList中获取随机单词?

public List<String> createList(int listSize) {
   Random rand = new Random();
   List<String> wordList = sourceWords.
      stream().
      limit(listSize).
      collect(Collectors.toList()); 

   return wordList;
}
Run Code Online (Sandbox Code Playgroud)

那么我如何以及在哪里使用我的随机数?

Adr*_*ebs 22

我找到了一个合适的解决方案.Random提供了一些返回流的方法.例如,创建随机整数流的整数(大小).

public List<String> createList(int listSize)
{
   Random rand = new Random();
   List<String> wordList = rand.
      ints(listSize, 0, sourceWords.size()).
      mapToObj(i -> sourceWords.get(i)).
      collect(Collectors.toList());

   return wordList;
}
Run Code Online (Sandbox Code Playgroud)

  • 使用此解决方案,您可能会在结果中重复单词,这可能是不合需要的.如果你的情况没问题,请编辑问题以明确说明. (5认同)
  • 这样,您的结果列表将比请求的更短.可能是`rand.ints(0,sourceWords.size()).distinct().limit(listSize).mapToObj(sourceWords :: get)`会更好. (5认同)

daS*_*der 10

我认为最优雅的方式是拥有一个特殊的收藏家.

我很确定你能保证每件物品被选中的机会相同的唯一方法就是收集,洗牌和重新流.这可以使用内置的Collectors.collectingAndThen(...)帮助程序轻松完成.

通过随机比较器或使用随机减速器进行排序,如在其他一些答案中所建议的那样,将导致非常偏向的随机性.

List<String> wordList = sourceWords.stream()
  .collect(Collectors.collectingAndThen(Collectors.toList(), collected -> {
      Collections.shuffle(collected);
      return collected.stream();
  }))
  .limit(listSize)
  .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

您可以将该shuffling收集器移动到辅助函数:

public class CollectorUtils {

    public static <T> Collector<T, ?, Stream<T>> toShuffledStream() {
        return Collectors.collectingAndThen(Collectors.toList(), collected -> {
            Collections.shuffle(collected);
            return collected.stream();
        });
    }

}
Run Code Online (Sandbox Code Playgroud)

我假设您正在寻找一种与其他流处理功能很好地集成的方法.所以遵循直截了当的解决方案并不是你想要的:)

Collections.shuffle(wordList)
return wordList.subList(0, limitSize)
Run Code Online (Sandbox Code Playgroud)