从Java中的列表中选择多个随机元素

Yok*_*hen 23 java random list

所以说我有

List<String> teamList = new LinkedList<String>()
teamList.add("team1");
teamList.add("team2");
teamList.add("team3");
teamList.add("team4");
teamList.add("team5");
teamList.add("team6");
Run Code Online (Sandbox Code Playgroud)

是否有一种简单的选择方法...以随机方式说明该列表中的6个元素中的3个而不选择相同的元素两次(或更多次)?

Ósc*_*pez 56

试试这个:

public static List<String> pickNRandom(List<String> lst, int n) {
    List<String> copy = new LinkedList<String>(lst);
    Collections.shuffle(copy);
    return copy.subList(0, n);
}
Run Code Online (Sandbox Code Playgroud)

我假设输入列表中没有重复的元素,我也采取了预防措施来改变副本,使原始列表不受干扰.它被称为这样:

List<String> randomPicks = pickNRandom(teamList, 3);
Run Code Online (Sandbox Code Playgroud)

  • 当您只需要3个元素时,对整个列表进行洗牌对于大型列表来说非常浪费. (5认同)
  • IndexOutOfBoundsException 的可用保护:返回 n &gt; copy.size() ?copy.subList(0, copy.size()) : copy.subList(0, n); (2认同)

das*_*ght 6

创建一组整数,并将0和列表长度减去1之间的随机数放入循环中,而集合的大小不等于所需的随机元素数.浏览集合,并选择集合中的数字所指示的列表元素.这样可以保持原始列表的完整性.


alf*_*alf 5

这种shuffle方法是最惯用的:在此之后,第一个K元素正是您所需要的.

如果K远小于列表的长度,您可能希望更快.在这种情况下,遍历列表,随机地将当前元素与其自身或其后的任何元素进行交换.在第K个元素之后,停止并返回K前缀:它将已经完全洗牌,您不需要关心列表的其余部分.

(显然,你想ArrayList在这里使用)


fin*_*nnw 5

您还可以使用水库采样

它的优点是您不需要提前知道源列表的大小(例如,如果给您一个Iterable而不是 a List。)而且,即使源列表不是随机访问的,就像LinkedList您的例子。


Hel*_*ira 5

这是使用 Java 流执行此操作的一种方法,无需创建原始列表的副本或对其进行打乱:

public static List<String> pickRandom(List<String> list, int n) {
    if (n > list.size()) {
        throw new IllegalArgumentException("not enough elements");
    }
    Random random = new Random();
    return IntStream
            .generate(() -> random.nextInt(list.size()))
            .distinct()
            .limit(n)
            .mapToObj(list::get)
            .collect(Collectors.toList());
}
Run Code Online (Sandbox Code Playgroud)

注意:当n太接近大型列表的列表大小时,它可能会变得低效。