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

时间:2011-12-04 21:31:21

标签: java list random

所以说我有

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

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

8 个答案:

答案 0 :(得分:55)

试试这个:

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);
}

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

List<String> randomPicks = pickNRandom(teamList, 3);

答案 1 :(得分:6)

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

答案 2 :(得分:5)

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

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

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

答案 3 :(得分:4)

您也可以使用reservoir sampling

它的优点是您无需事先知道源列表的大小(例如,如果您获得Iterable而不是List。)即使在源列表不是随机访问,如示例中的LinkedList

答案 4 :(得分:2)

使用

Collections.shuffle(teamList);

随机化列表,然后通过teamList.remove(0);

从列表中一次删除一个团队

例如:

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

  java.util.Collections.shuffle(teamList);

  String[] chosen3 = new String[3];
  for (int i = 0; i < chosen3.length && teamList.size() > 0; i++) {
     chosen3[i] = teamList.remove(0);
  }

答案 5 :(得分:2)

所有好的想法,但洗牌是昂贵的。更有效的方法(IMO)将进行计数控制循环并在0和n之间选择随机int;其中n最初等于列表的长度。

在循环的每次迭代中,将所选项目与列表中n-1的项目交换,并将n递减1。这样您就可以避免两次选择相同的元素,而不必保留所选项目的单独列表。

答案 6 :(得分:2)

以下是使用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());
}

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

答案 7 :(得分:0)

int[] getRandoms(int[] ranges, int n, int[] excepts) {
    int min = ranges[0];
    int max = ranges[1];

    int[] results = new int[n];
    for (int i = 0; i < n; i++) {
        int randomValue = new Random().nextInt(max - min + 1) + min;
        if (ArrayUtils.contains(results, randomValue) || ArrayUtils.contains(excepts, randomValue)) {
            i--;
        } else {
            results[i] = randomValue;
        }
    }
    return results;
}

util class

public static class ArrayUtils {

    public static boolean contains(int[] array, int elem) {
        return getArrayIndex(array, elem) != -1;
    }

    /** Return the index of {@code needle} in the {@code array}, or else {@code -1} */
    public static int getArrayIndex(int[] array, int needle) {
        if (array == null) {
            return -1;
        }
        for (int i = 0; i < array.length; ++i) {
            if (array[i] == needle) {
                return i;
            }
        }
        return -1;
    }
}
使用

int[] randomPositions = getRandoms(new int[]{0,list.size()-1}, 3, new int[]{0,1});

除了第0项和第1项

之外,它会随机列出3个项目