Выберите несколько случайных элементов из списка в Java
Так сказать, у меня
List<String> teamList = new LinkedList<String>()
teamList.add("team1");
teamList.add("team2");
teamList.add("team3");
teamList.add("team4");
teamList.add("team5");
teamList.add("team6");
Есть ли простой способ выбора... скажите 3 из 6 элементов в этом списке рандомизированным образом, не выбирая один и тот же элемент дважды (или более раз)?
Ответы
Ответ 1
Попробуйте следующее:
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);
Ответ 2
Создайте набор int и поместите случайные числа между 0 и длиной списка минус один в него в цикле, а размер набора не равен желаемому количеству случайных элементов. Пройдите через набор и выберите элементы списка, как указано числами в наборе. Таким образом, ваш исходный список не будет сохранен.
Ответ 3
Подход shuffle
является самым идиоматическим: после этого первые элементы K - это именно то, что вам нужно.
Если K намного меньше длины списка, вы можете захотеть быстрее. В этом случае перебирайте список, случайно обменивая текущий элемент с собой или с любым из элементов после него. После K-го элемента остановите и верните K-префикс: он будет уже полностью перетасован, и вам не нужно заботиться о остальной части списка.
(очевидно, вы хотели бы использовать ArrayList
здесь)
Ответ 4
Вы также можете использовать выборку коллектора.
Преимущество состоит в том, что вам не нужно заранее знать размер исходного списка (например, если вам предоставляется Iterable
вместо List
.) Также он эффективен, даже если исходный список не произвольный доступ, например LinkedList
в вашем примере.
Ответ 5
Используйте
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);
}
Ответ 6
Все хорошие идеи, но перетасовка - это дорого. Более эффективный метод (IMO) будет выполнять цикл, контролируемый счетчиком, и выбор случайного int между 0 и n; где n изначально равно длине вашего списка.
В каждой итерации цикла вы меняете выбранный элемент с элементом в n-1 в списке и уменьшаете n на единицу. Таким образом, вы избегаете выбора одного и того же элемента два раза и не должны содержать отдельный список выбранных элементов.
Ответ 7
Вот как это сделать, используя потоки 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
слишком близко к размеру списка для огромных списков.
Ответ 8
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;
}
Использовать класс
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});
он будет случайным 3 пункта в вашем списке, кроме пункта 0 и пункта 1