繁体   English   中英

为每个数组值生成一个唯一的随机数

[英]Generate a unique random number for each array value

我有此方法,此方法为该方法中列出的每个数组值生成一个数字(1-10)。 我希望将整个数字集显示为一组唯一的数字。 这该怎么做?

public static int generateNumbers(int[] lotteryNumbers) {

    Random randNum = new Random();

    lotteryNumbers[0] = randNum.nextInt(10);
    lotteryNumbers[1] = randNum.nextInt(10);
    lotteryNumbers[2] = randNum.nextInt(10);
    lotteryNumbers[3] = randNum.nextInt(10);
    lotteryNumbers[4] = randNum.nextInt(10);

    return lotteryNumbers[4];
}

一个简单的解决方案是生成10位数字的列表,对列表进行随机排列并获得前五个元素:

List<Integer> list = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
    list.add(i);
}
Collections.shuffle(list);
Integer[] lotteryNumbers = list.subList(0, 5).toArray(new Integer[10]);

Collections.shuffle(list)是一种实用程序方法,用于随机排列给定列表的位置。

如果您使用的是Java 8,可以这样写:

List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList());
Collections.shuffle(list);
int[] loterryNumbers = list.subList(0, 5).stream().mapToInt(i -> i).toArray();

天真的技巧是在要“随机播放”的集合中随机选择:

public static int[] generateNumbers(int exclusiveMaxValue) {
    List<Integer> values = new ArrayList<>(exclusiveMaxValue);
    for (int i=0 ; i<values.size() ; i++) values.add(i);

    int[] result = new int[exclusiveMaxValue];
    Random rd = new Random();
    for (int i=0 ; i<result.length ; i++) {
       result[i] = values.remove(rd.nextInt(values.size()));
    }
    return result;
}

但是, List.remove通常为O(n) ,因此整个方法是二次方的,这非常昂贵。 您可以通过简单地交换元素来在O(n)执行随机播放(这就是Collections.shuffle作用):

public static int[] generateNumbers(int exclusiveMaxValue) {
    int[] result = new int[exclusiveMaxValue];
    for (int i=0 ; i<result.length ; i++) result[i] = i;

    Random rd = new Random();
    for (int i=result.length - 1 ; i>=0 ; i--) {
       swap(result, i, rd.nextInt(i + 1));
    }
    return result;
}

private static swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

此方法生成范围为[0,N -1]的唯一数字的长度N的序列。

public static int[] generateNumbers(int length) {
    final int[] array = new int[length];
    for (int i = 0; i < length; ++i) {
        array[i] = i;
    }
    shuffle(array);
    return array;
}

对于改组,使用了Fisher-Yates算法:

public static void shuffle(final int[] array) {
    final Random random = new Random();
    for (int i = array.length - 1; i > 0; --i) {
        final int randomIdx = random.nextInt(i + 1);
        final int temp = array[i];
        array[i] = array[randomIdx];
        array[randomIdx] = temp;
    }
}
  • 感谢( Ronald Fisher和Frank Yates ),算法的时间复杂度为O(n)
  • 此实现适用于数组(具有基元),而不适用于集合(具有将整数类型int的值包装在对象中的Integer类的实例)-如果数组大小足够大就很重要

这是使用集并填充它直到其增长到所需大小的另一种方法。 它生成numbersToDraw最小最大 (包括)范围内的不同随机数。 它还保留数字绘制的顺序(这是LinkedHashSet的作用)。

private static Set<Integer> drawNumbers(int min, int max, int numbersToDraw) {
    if (max < min) {
        throw new IllegalArgumentException("Minimum must be less than maximum.");
    }
    if (max < 0 || min < 0) {
        throw new IllegalArgumentException("Both range numbers must be positive.");
    }
    final int countOfNumbers = max - min + 1;
    if (countOfNumbers < numbersToDraw) {
        throw new IllegalArgumentException("Range is not big enough.");
    }
    final Random randomizer = new SecureRandom();
    final Set<Integer> numbersDrawn = new LinkedHashSet<>();
    while (numbersDrawn.size() < numbersToDraw) {
        final int randomNumber = min + randomizer.nextInt(countOfNumbers);
        numbersDrawn.add(randomNumber);
    }
    return numbersDrawn;
}

如果您不需要数字唯一,则可以在Java 8中使用它:

final Random randomizer = new SecureRandom();

final List<Integer> numbersDrawn = IntStream
        .range(0, numbersToDraw)
        .mapToObj(i -> min + randomizer.nextInt(max - min + 1))
        .collect(Collectors.toList());

如果您不要求数字是唯一的,那么您要打印它们的不同值(这是您的原始问题吗?):

final Random randomizer = new SecureRandom();

final Set<Integer> numbersDrawn = IntStream
        .range(0, numbersToDraw)
        .mapToObj(i -> min + randomizer.nextInt(max - min + 1))
        .collect(Collectors.toSet());

针对您的具体情况,还有另一种选择:

final Set<Integer> distinctNumbers = Arrays
  .stream(lotteryNumbers)
  .distinct() // you can leave this as the set is distinct automatically
  .boxed()
  .collect(Collectors.toSet());

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM