Java 从列表中随机抽取n个元素<;E>;?
如何从Java 从列表中随机抽取n个元素<;E>;?,java,algorithm,random,sampling,Java,Algorithm,Random,Sampling,如何从ArrayList中获取n个随机元素?理想情况下,我希望能够连续调用take()方法来获取另一个x元素,而无需替换。如果您希望从列表中连续选取n个元素,并且能够这样做而无需一次又一次地替换,您可能最好随机排列这些元素,然后把大块的东西分成n块。如果随机排列列表,则可以保证所选每个块的统计随机性。也许最简单的方法就是使用。主要有两种方法 使用: 它使您能够通过递增索引(假设列表本身包含唯一元素)获取n唯一元素 如果您想知道是否有Java8流方法;不,没有内置的。标准API中没有比较器#ra
ArrayList
中获取n个随机元素?理想情况下,我希望能够连续调用take()
方法来获取另一个x元素,而无需替换。如果您希望从列表中连续选取n个元素,并且能够这样做而无需一次又一次地替换,您可能最好随机排列这些元素,然后把大块的东西分成n块。如果随机排列列表,则可以保证所选每个块的统计随机性。也许最简单的方法就是使用。主要有两种方法
n
唯一元素如果您想知道是否有Java8流方法;不,没有内置的。标准API中没有比较器#randomOrder()这样的东西(还没有?)。您可以在满足严格的
Comparator
契约的同时尝试以下方法(尽管分发非常糟糕):
List List=createItSomehow();
int random=new random().nextInt();
Foo Foo=list.stream().sorted(Comparator.comparingInt(o->System.identityHashCode(o)^random)).findFirst().get();
最好使用
Collections#shuffle()
。一种公平的方法是在第n次迭代时遍历列表,计算是否选择第n个元素的概率,该概率基本上是仍然需要选择的项目数与列表其余部分中可用元素数的分数。例如:
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;
}
publicstatict[]pickSample(T[]population,int-nsamplesneed,Random r){
T[]ret=(T[])Array.newInstance(population.getClass().getComponentType(),
不需要);
int nPicked=0,i=0,nLeft=population.length;
而(nsamplesneed>0){
int rand=r.nextInt(nLeft);
如果(随机数
(这段代码是从我不久前写的一个页面复制的。)简单明了
// 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;
//定义ArrayList以保存整数对象
ArrayList ArrayList=新的ArrayList();
对于(int i=0;i
使用以下类别:
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;
}
}
import java.util.Enumeration;
导入java.util.Random;
公共类RandomPermuteIterator实现枚举{
INTC=1013904223,a=1664525;
长种子,N,m,次之;
布尔hasNext=true;
公共随机PermuteIterator(长N)引发异常{
if(N Math.pow(2,62))抛出新异常(“不支持的大小:+N”);
这个,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));
}
公共静态void main(字符串[]args)引发异常{
随机置换器r=新的随机置换器(100);
while(r.hasMoreElements())System.out.print(r.nextElement()+);
}
@凌驾
公共布尔值hasMoreElements(){
返回hasNext;
}
@凌驾
公共长期nextElement(){
下一步=(a*下一步+c)%m;
而(next>=N)next=(a*next+c)%m;
如果(next==seed)hasNext=false;
下一步返回;
}
}
到目前为止,大多数建议的解决方案都建议通过检查唯一性进行完整列表洗牌或连续随机挑选,并在需要时重试
但是,我们可以利用Durstenfeld算法(当今最流行的Fisher-Yates变体)
Durstenfeld的解决方案是将“敲打”的数字移到最后
通过在每个位置将其与最后一个未固定的编号进行交换来创建列表
迭代
由于上述原因,我们不需要洗牌整个列表,而是根据返回所需的元素数运行循环。如果使用完美随机函数,该算法确保列表末尾的最后N个元素是100%随机的
在我们需要从数组/列表中选择预定(最大)数量的随机元素的许多真实场景中,这种优化方法对于各种纸牌游戏非常有用,例如德克萨斯扑克,在其中,您事先知道每场游戏要使用的牌数;牌组中通常只需要有限数量的牌
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());
}
publicstaticlist-picknrandomements(List-List,int-n,Random-r){
int length=list.size();
如果(长度=长度-n;--i)
{
集合交换(列表,i,r.nextInt(i+1));
}
返回列表.子列表(长度-n,长度);
}
公共静态列表picknrandomements(列表列表,int n){
返回picknrandomements(list,n,ThreadLocalRandom.current());
}
继续选择随机元素,并确保不再选择相同的元素:
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;
}
public static List selectRandomElements(列表列表,整数金额)
{
//避免僵局
如果(金额>=list.size())
{
退货清单;
}
所选列表=新建ArrayList();
随机=新随机();
int listSize=list.size();
//在我们得到要求的数量之前,随机购买一件物品
while(selected.size()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;
}
}
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());
}
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;
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class NRandomItem<T> {
private final List<T> initialList;
public NRandomItem(List<T> list) {
this.initialList = list;
}
/**
* Do not provide seed, if you want different items on each run.
*
* @param numberOfItem
* @return
*/
public List<T> retrieve(int numberOfItem) {
int seed = new Random().nextInt();
return retrieve(seed, numberOfItem);
}
/**
* The same seed will always return the same random list.
*
* @param seed,
* the seed of random item generator.
* @param numberOfItem,
* the number of items to be retrieved from the list
* @return the list of random items
*/
public List<T> retrieve(int seed, int numberOfItem) {
Random rand = new Random(seed);
Collections.shuffle(initialList, rand);
// Create new list with the number of item size
List<T> newList = new ArrayList<>();
for (int i = 0; i < numberOfItem; i++) {
newList.add(initialList.get(i));
}
return newList;
}
public static void main(String[] args) {
List<String> l1 = Arrays.asList("Foo", "Bar", "Baz", "Qux");
int seedValue = 10;
NRandomItem<String> r1 = new NRandomItem<>(l1);
System.out.println(String.format("%s", r1.retrieve(seedValue, 2)));
}
}
private static <E> List<E> pickRandom(List<E> list, int n) {
return new Random().ints(n, 0, list.size()).mapToObj(list::get).collect(Collectors.toList());
}
static Random rand = new Random();
static <T> List<T> randomSample(List<T> list, int size) {
List<T> sample = new ArrayList<>();
for (int sortedSampleIndices[] = new int[size], i = 0; i < size; i++) {
int index = rand.nextInt(list.size() - i);
int j = 0;
for (; j < i && index >= sortedSampleIndices[j]; j++)
index++;
sample.add(list.get(index));
for (; j <= i; j++) {
int temp = sortedSampleIndices[j];
sortedSampleIndices[j] = index;
index = temp;
}
}
return sample;
}
func getRandomElementsFrom(array: [Int], count: Int = 8) -> [Int] {
if array.count <= count {
return array
}
var mapper = [Int: Int]()
var results = [Int]()
for i in 0..<count {
let randomIndex = Int.random(in: 0..<array.count - i)
if let existing = mapper[randomIndex] {
results.append(array[existing])
} else {
let element = array[randomIndex]
results.append(element)
}
let targetIndex = array.count - 1 - i
mapper[randomIndex] = mapper[targetIndex] ?? targetIndex
}
return results
}
public static <T> List<T> nextRandomN(List<T> list, int n) {
return Stream
.generate(() -> list.remove((int) (list.size() * Math.random())))
.limit(Math.min(list.size(), n))
.collect(Collectors.toList());
}
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
System.out.println(nextRandomN(list, 3).toString());
System.out.println(nextRandomN(list, 3).toString());
System.out.println(nextRandomN(list, 3).toString());
System.out.println(nextRandomN(list, 3).toString());
[8, 2, 3]
[4, 10, 7]
[1, 5, 9]
[6]