我目前正在寻找最好的方法,因此在n个整数范围内选择x个唯一的整数。这就像多次执行Random.nextInt(range)
一样,但它永远不应该选择两次相同的int。
如果它发生x > n
,那么结果将只包含n个整数
我自己尝试这样做,而且我目前基于Fisher / Yates shuffle做了这个:
private static final Random R = new Random();
public static int[] distinctRandoms(int nb, int max) {
int[] all = new int[max];
for (int i = 0; i < all.length; i++) {
all[i] = i;
}
if (max <= nb) {
return all;
}
int index;
int[] result = new int[nb];
for (int j = 0, k = all.length - 1; k > 0 && j < nb; k--, j++) {
index = R.nextInt(k + 1);
result[j] = all[index]; // save element
all[index] = all[k]; // overwrite chosen with last element
}
return result;
}
它的工作和性能似乎很好,但我不禁想到仍然必须有一些更高性能的方式,并且我正在重新发明轮子。如果nb > (max / 2)
(删除元素而不是选择元素),我考虑过以不同的方式做事,但由于你不能在java中截断数组,你仍然最终会复制你需要的所有元素。
如果nb = max-1
有没有内置的方法可以在java中有效地随机选择不同的int?
修改1:
高性能的意思是节省时间。我希望它快。我将主要使用小套的randoms。
编辑2:
我尝试使用shuffle,但由于所有额外的对象创建,它在时间上要贵得多。
public static Integer[] distinctRandoms2(int nb, int max) {
ArrayList<Integer> all = new ArrayList<Integer>(max);
for (int i = 0; i < max; i++) {
all.add(i);
}
if (max <= nb) {
return all.toArray(new Integer[max]);
}
Collections.shuffle(all);
return all.subList(0, nb).toArray(new Integer[nb]);
}
答案 0 :(得分:3)
您可以使用java.util.Collections
课程中的shuffle方法。
只需创建从0
到x-1
的整数列表,然后在其上调用shuffle
方法并获取前nb
个元素。
当shuffle
接近nb
时,使用max
方法有意义。因此,遵循成对参数会很好:
nb=70, max=100
nb=900, max=1000
nb=9000, max=10000
但不太适合:
nb=10, max=10^8
nb=100, max=10^9
将上述方法(使用shuffle
)与其他答案中的Floyd算法结合起来是个好主意。算法的选择应基于比率nb/max
。应谨慎选择边界比率。
答案 1 :(得分:3)
您可以使用Floyd的算法。如果要选择的元素数量小于其范围,则它比混洗更有效。
private static final Random random = new Random();
/**
* Converts a set of Integer to an array of int.
*/
private static int[] setToArray(Set<Integer> aSet) {
int[] result = new int[aSet.size()];
int index = 0;
for (int number : aSet) {
result[index] = number;
index++;
}
return result;
}
/**
* Generates an array of min(count, maxValue) distinct random ints
* from [0, maxValue - 1] range.
* @param count The number of elements to be generated.
* @param maxValue The upper bound of the range(exclusively).
*/
public static int[] getDistinctRandomNumbers(int count, int maxValue) {
Set<Integer> was = new HashSet<>();
for (int i = Math.max(0, maxValue - count); i < maxValue; i++) {
int curr = i == 0 ? 0 : random.nextInt(i);
if (was.contains(curr))
curr = i;
was.add(curr);
}
return setToArray(was);
}
它具有O(count)
时间和空间复杂度,其中count
是应生成的不同整数的数量。
答案 2 :(得分:2)
这取决于Performant
和Random
的含义。
如果您确实需要费用为O(1)
或类似费用的内容,则可以使用Linear feedback shift register或LFSR。它使用前一个数字上的简单XOR
运算生成一个随机数字序列(即统计随机但在理论上可预测),因此可能是最快的机制。
如果您想要任何n位数,这种方法最合适。通过丢弃超出所需范围的数量来限制数量范围可能会降低性能。
答案 3 :(得分:1)
如果通过&#34;小组的randoms&#34;你的意思是max
很小,Collections#shuffle
方法可能就像你能得到的一样好。
如果max
可以是任意大,但nb
很小,那么使用HashSet
可能是您的最佳选择,尽管您会有一些装箱/取消装箱费用。如果您想避免这笔费用,可以尝试使用an IntHashSet
或HashSet
的类似原始专业。