在这种情况下,MAX仅为5,因此我可以一张一张地检查重复项,但是如何以更简单的方式进行检查呢?例如,如果MAX的值为20,该怎么办?谢谢。
int MAX = 5; for (i = 1 , i <= MAX; i++) { drawNum[1] = (int)(Math.random()*MAX)+1; while (drawNum[2] == drawNum[1]) { drawNum[2] = (int)(Math.random()*MAX)+1; } while ((drawNum[3] == drawNum[1]) || (drawNum[3] == drawNum[2]) ) { drawNum[3] = (int)(Math.random()*MAX)+1; } while ((drawNum[4] == drawNum[1]) || (drawNum[4] == drawNum[2]) || (drawNum[4] == drawNum[3]) ) { drawNum[4] = (int)(Math.random()*MAX)+1; } while ((drawNum[5] == drawNum[1]) || (drawNum[5] == drawNum[2]) || (drawNum[5] == drawNum[3]) || (drawNum[5] == drawNum[4]) ) { drawNum[5] = (int)(Math.random()*MAX)+1; } }
最简单的方法是创建一个可能数字的列表(1..20或任何数字),然后用对其进行混洗Collections.shuffle。然后,只需考虑你想要的许多元素。如果你的范围最终等于你需要的元素数量(例如,用于洗牌的卡片),则这非常好。
Collections.shuffle
如果你想要(说)1..10,000范围内的10个随机元素,那么效果就不太好-你最终会不必要地进行大量工作。到那时,最好保留到目前为止已生成的一组值,并保持循环生成数字直到下一个不存在为止:
if (max < numbersNeeded) { throw new IllegalArgumentException("Can't ask for more numbers than are available"); } Random rng = new Random(); // Ideally just create one instance globally // Note: use LinkedHashSet to maintain insertion order Set<Integer> generated = new LinkedHashSet<Integer>(); while (generated.size() < numbersNeeded) { Integer next = rng.nextInt(max) + 1; // As we're adding to a set, this will automatically do a containment check generated.add(next); }
但是,请谨慎选择设置-我非常有意地使用LinkedHashSet它,因为它会保持插入顺序,我们在这里关心它。
另一种选择是通过每次减小范围并补偿现有值来始终取得进展。因此,举例来说,假设你要使用0..9范围内的3个值。在第一次迭代中,你将生成0..9范围内的任何数字-假设你生成了4。
在第二次迭代中,你将生成一个范围为0..8的数字。如果生成的数字小于4,则应保持原样…否则将其添加一个。这样得到的结果范围是0..9,而不是4。假设我们以这种方式得到7。
在第三次迭代中,你将生成一个范围为0..7的数字。如果生成的数字小于4,则将其保持原样。如果是4或5,则要加1。如果是6或7,则要加两个。这样,结果范围是0..9,没有4或6。