每次迭代时从int数组中选择不同的随机元素?

时间:2014-12-07 00:20:52

标签: java arrays random

我有一个int向量,例如int[] A = {6, 1, 5, 3, 4, 2},我需要在三个步骤中随机选取两个不同的元素,每个步骤应该从其他步骤中提取不同的元素。

例如:

  1. 选择2,5
  2. 选择6,3
  3. 选择4,1
  4. 我尝试这样做,但我多次失败。我真的很感激任何帮助。 这是我的最后一段代码。

    public class T8 {
        public static void main(String[] args) {
            int n=5,   d=2, r,  i,  j;
            int[] B = new int [d];
            Random rand=new Random(); 
            System.out.println("d = "+d);
            Integer[] A = {10,12,3,4,5};
            List<Integer> list = new ArrayList<Integer>(Arrays.asList(A));
            for(j=0; j<d; j++){
                r = rand.nextInt(n);
                B[j] = A[r];
                System.out.print(B[j]+"   ");
                list.remove(r);
                A = list.toArray(new Integer[0]);
                n=n-1;
            }
    
            System.out.println("");
            for(j=0; j<n; j++){
                System.out.print(A[j]+"   ");
            }
        }
    }
    

2 个答案:

答案 0 :(得分:0)

非最佳方法:您可以使用random.nextInt并且每次生成随机数时检查它是否唯一,如果不生成新的随机索引。 E.g。

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class RandomPicker {

    public static void main(String[] args) {

        int[] arr = {6, 1, 5, 3, 4, 2};
        Random random = new Random();
        Set<Integer> randoms = new HashSet<>();
        while (arr.length != randoms.size()) {
            int i = nextRandomIndex(arr, random, randoms);
            int j = nextRandomIndex(arr, random, randoms);
            System.out.printf("%d,%d\n", arr[i], arr[j]);
        }
    }

    private static int nextRandomIndex(int[] arr, Random random, Set<Integer> randoms) {
        int i = random.nextInt(arr.length);
        while (randoms.contains(i)) {
            i= random.nextInt(arr.length);
        }
        randoms.add(i);
        return i;
    }
}

可能的输出

4,1
6,3
5,2

更好的方法是对数组进行混洗,然后对其进行迭代(如果您不想修改数组,则将原始数组的副本传递给shuffle方法)。 E.g。

import java.util.Arrays;
import java.util.Random;

public class RandomPicker {

    public static void main(String[] args) {

        int[] arr = {6, 1, 5, 3, 4, 2};
        int[] copy = Arrays.copyOf(arr, arr.length);
        shuffle(copy);
        int index = 0;
        for (int i = 0; i < arr.length / 2; i++) {
            System.out.printf("%d, %d\n",copy[index], copy[++index]);
        }
    }

    private static void shuffle(int[] arr)
    {
        int index;
        int temp;
        Random rand = new Random();
        int i = arr.length - 1;
        while ( i > 0)
        {
            index = rand.nextInt(i + 1);
            temp = arr[index];
            arr[index] = arr[i];
            arr[i] = temp;
            i--;
        }
    }
}

答案 1 :(得分:0)

许多方法可以做到这一点:

  1. 将数组元素复制到List中,然后从列表中随机删除元素。

  2. 使用(弱)伪随机数生成器以可预测的方式遍历所有索引。

  3. 创建之前返回的所有元素的HashSet

  4. 使用shuffle方法就地对输入数组进行随机播放,然后从索引0开始一次返回一个元素,直到达到length - 1

  5. 如果您无法更改输入数组,则创建一个填充了值0length - 1的数组,随机播放该数组,然后使用其遍历该数组值作为第一个数组的索引。

  6. @ sol4me的解决方案(上面是3.和5.的混合)有一个有趣的属性。计算行为是概率性的:

    • 当你到达序列的末尾时,找到并返回一个之前没有使用的索引所花费的时间会增长,并且会惊恐地发现#34;

    • 理论上最坏情况的行为是nextRandomIndex永远不会终止。 (只有当您的随机数生成器有偏差时才会发生这种情况。)

    • 对于&#34;完美&#34;随机数生成器,nextRandomIndex执行的迭代次数是有限的,但我们不能在其上设置上限。

    • 对于伪随机数生成器,生成器的循环长度是迭代次数的上限。


    您尝试的解决方案接近我建议的第一个解决方案。但有一个问题是

        List<Integer> list = new ArrayList<Integer>(Arrays.asList(A));
    

    正在创建一个&#34;视图&#34;到无法更改长度的数组。如果您创建ArrayList然后数组元素复制到列表中,则无法获得您在remove中看到的例外情况。

    另一个问题是:

        A = list.toArray(new Integer[0]);
    

    非常低效。没有必要将列表转换回数组。请保留下次列表。