Как я могу взять n случайных элементов из ArrayList<E>
? В идеале я хотел бы сделать последовательные вызовы метода take()
для получения других элементов x без замены.Возьмите n случайных элементов из списка <E>?
ответ
Два основных способа.
Использование
Random#nextInt(int)
:List<Foo> list = createItSomehow(); Random random = new Random(); Foo foo = list.get(random.nextInt(list.size()));
Это, однако, не гарантирует, что последовательные вызовы
n
возвращает уникальные элементы.Использование
Collections#shuffle()
:List<Foo> list = createItSomehow(); Collections.shuffle(list); Foo foo = list.get(0);
Это позволяет получить
n
уникальные элементы от увеличивающегося индекса (при условии, что сам список содержит уникальные элементы).
В случае, если вам интересно, если есть поток подход Java 8; нет, нет встроенного. Нет такой вещи, как Comparator#randomOrder()
в стандартном API (пока?). Вы могли бы попробовать что-то, как показано ниже, при этом отвечая строгим Comparator
контракт (хотя распределение довольно ужасно):
List<Foo> list = createItSomehow();
int random = new Random().nextInt();
Foo foo = list.stream().sorted(Comparator.comparingInt(o -> System.identityHashCode(o)^random)).findFirst().get();
Лучше использования Collections#shuffle()
вместо этого.
У меня есть список из 4000 слов, и я должен получить 5 слов из этого списка каждый раз, когда я нажимаю кнопку обновления, использую второй вариант вашего ответа. Насколько это гарантирует, что я буду получать уникальные значения все время, то есть какая вероятность? – Prateek
@Prateek: Если у вас есть вопрос, нажмите кнопку «Спросить вопрос». Не нажимайте кнопку «Добавить комментарий» или «Опубликовать ответ». – BalusC
Я знаю, когда использовать эту кнопку, мой комментарий несколько связан с вашим уже отправленным ответом, поэтому я не хотел создавать новый поток if и искал ответ inline, спасибо в любом случае. – Prateek
Если вы хотите последовательно выбрать n элементов из списка и быть в состоянии сделать это без замены снова и снова, вы, вероятно, лучше всего произвольно переставляете элементы, а затем снимаете куски в блоках n. Если вы произвольно переставляете список, вы гарантируете статистическую случайность для каждого выбранного вами блока. Возможно, самый простой способ сделать это - использовать Collections.shuffle
.
И самый простой способ сделать это - вызвать java.util.Collections.shuffle() – biziclop
Справедливый способ сделать это - пройти через список, на n-й итерации, рассчитывая вероятность того, следует ли выбрать n-й элемент, который по существу является долей числа элементов, которые вам еще нужно выбрать количество элементов, доступных в остальной части списка. Например: (. Этот код скопирован со страницы я написал некоторое время назад на picking a random sample from a list)
public static <T> T[] pickSample(T[] population, int nSamplesNeeded, Random r) {
T[] ret = (T[]) Array.newInstance(population.getClass().getComponentType(),
nSamplesNeeded);
int nPicked = 0, i = 0, nLeft = population.length;
while (nSamplesNeeded > 0) {
int rand = r.nextInt(nLeft);
if (rand < nSamplesNeeded) {
ret[nPicked++] = population[i];
nSamplesNeeded--;
}
nLeft--;
i++;
}
return ret;
}
Простой и понятный
// define ArrayList to hold Integer objects
ArrayList<Integer> arrayList = new ArrayList<>();
for (int i = 0; i < maxRange; i++) {
arrayList.add(i + 1);
}
// shuffle list
Collections.shuffle(arrayList);
// adding defined amount of numbers to target list
ArrayList<Integer> targetList = new ArrayList<>();
for (int j = 0; j < amount; j++) {
targetList.add(arrayList.get(j));
}
return targetList;
Используйте следующий класс:
import java.util.Enumeration;
import java.util.Random;
public class RandomPermuteIterator implements Enumeration<Long> {
int c = 1013904223, a = 1664525;
long seed, N, m, next;
boolean hasNext = true;
public RandomPermuteIterator(long N) throws Exception {
if (N <= 0 || N > Math.pow(2, 62)) throw new Exception("Unsupported size: " + N);
this.N = N;
m = (long) Math.pow(2, Math.ceil(Math.log(N)/Math.log(2)));
next = seed = new Random().nextInt((int) Math.min(N, Integer.MAX_VALUE));
}
public static void main(String[] args) throws Exception {
RandomPermuteIterator r = new RandomPermuteIterator(100);
while (r.hasMoreElements()) System.out.print(r.nextElement() + " ");
}
@Override
public boolean hasMoreElements() {
return hasNext;
}
@Override
public Long nextElement() {
next = (a * next + c) % m;
while (next >= N) next = (a * next + c) % m;
if (next == seed) hasNext = false;
return next;
}
}
Большинство предлагаемых решений до сих пор предлагают либо полный перетасовать список, либо последовательно выбирая дом, проверяя уникальность и, если потребуется, повторите попытку.
Но мы можем воспользоваться алгоритмом Дурстенфельда (самым популярным вариантом Fisher-Yates в наши дни).
решения Durstenfeld является переместить «поразивший» номер до конца списка путем замены их с последним незатронутым номером на каждой итерации .
В связи с вышеизложенным, нам не нужно перетасовать весь список, но запустить цикл на столько шагов, как количество элементов, необходимых для возврата. Алгоритм гарантирует, что последние N элементов в конце списка на 100% случайны, если мы используем совершенную случайную функцию.
Среди многих сценариев реального мира, где нам нужно выбрать предопределенное (максимальное) количество случайных элементов из массивов/списков, этот оптимизированный метод очень полезен для различных карточных игр, таких как Texas Poker, где вы, априори знать количество карт, которые будут использоваться за игру; из колоды обычно требуется ограниченное количество карточек.
public static <E> List<E> pickNRandomElements(List<E> list, int n, Random r) {
int length = list.size();
if (length < n) return null;
//We don't need to shuffle the whole list
for (int i = length - 1; i >= length - n; --i)
{
Collections.swap(list, i , r.nextInt(i + 1));
}
return list.subList(length - n, length);
}
public static <E> List<E> pickNRandomElements(List<E> list, int n) {
return pickNRandomElements(list, n, ThreadLocalRandom.current());
}
Спасибо, что указали это. У меня есть ситуация, когда мне нужно удалить небольшое количество элементов из большого списка, и я был уверен, что перетасовка всего списка - не лучший способ сделать это, но я все время зависал о том, как удалить несколько элементов из список одним махом. Сворачивание их до конца списка, а затем его усечение - изящное решение. – Matt
Keep выбрать случайный элемент и убедитесь, что вы не выбрали один и тот же элемент снова:
public static <E> List<E> selectRandomElements(List<E> list, int amount)
{
// Avoid a deadlock
if (amount >= list.size())
{
return list;
}
List<E> selected = new ArrayList<>();
Random random = new Random();
int listSize = list.size();
// Get a random item until we got the requested amount
while (selected.size() < amount)
{
int randomIndex = random.nextInt(listSize);
E element = list.get(randomIndex);
if (!selected.contains(element))
{
selected.add(element);
}
}
return selected;
}
В теории это может работать бесконечно, но на практике это прекрасно. Чем ближе вы получаете весь исходный список, тем медленнее время выполнения этого становится очевидным, но это не вопрос выбора случайного подсписка, не так ли?
- 1. Возьмите n элементов из коллекции
- 2. Возьмите n элементов в случайном порядке из списка
- 3. Возьмите первые n элементов из System.Collections.Generic.IEnumerable
- 4. Возьмите N элементы из списка на условиях
- 5. Как взять n случайных элементов из JSON
- 6. Пролога: Возьмите первые «N» элементы списка
- 7. алгоритм для выбора N случайных элементов из списка <T> в C#
- 8. Entity Framework Возьмите N элементов детской коллекции
- 9. Как извлечь N случайных разных элементов из набора уникальных элементов?
- 10. Создание новых случайных элементов из списка
- 11. Возьмите (n) символы из строки
- 12. Получение n случайных элементов в массиве
- 13. Возьмите 10 случайных строк из лучших 100
- 14. генерации случайных элементов списка с правилами
- 15. Выберите N элементов из списка в Прологе
- 16. r-concatenate для n элементов из списка
- 17. Удалить все N элементов из списка
- 18. Удаление n числа элементов из списка
- 19. Захватить последние n элементов из списка C#
- 20. Определение минимума списка из n элементов
- 21. Rails/ActiveRecord - найти N случайных элементов
- 22. Linq - Возьмите x-количество отдельных элементов из списка
- 23. Нарисуйте n случайных элементов (без замены) из контейнера stl
- 24. Возьмите из списка при увеличении
- 25. Swift + CoreData. Получить N случайных объектов из БД. N << size (DB)
- 26. Возьмите элементы из элементов в списке строк
- 27. Создание списка из N случайных чисел между диапазоном чисел
- 28. Выберите n случайных чисел из отсортированного списка чисел
- 29. Удалить последние N элементов списка
- 30. Возьмите N непустых предметов из набора clojure
что взять() в ArrayList? – Nishant
что у вас есть? Если вы получите еще один элемент x, вы можете снова выбрать элементы из предыдущего набора или все время должны быть разными, пока не будут выбраны ВСЕ элементы? (Затем, что дальше?) –
Без замены. Когда у вас больше нет, вы ничего не получите. –