0

I have here a 2D Array I populate with random numbers. I populate my array as follows:

for(int i = 0; i < 3; i++)
{
    for(int j = 0; j < 5; j++)
    {
        nums[i][j] = 1 + (int)(Math.random() * 60);
    }
}

I want my array to have numbers between 0 and 60, hence the:

* 60

I display my numbers like this:

System.out.println("Nums are: " + nums[0][0]+ " " + nums[0][1]+ " " + nums[0][2]+ " " + nums[0][3]+ " " + nums[0][4]);

and the output looks like this

Nums are: 43 6 32 6 12

I want to populate my array with Random numbers, but I don't want it to have matching numbers, so for this instance the number 6 is in the array twice. I want to remove the duplicates from the array or just not put them in the array at all.

The way I was thinking of doing this was by having 2 additional for loops within my loops with a greater value than 0, this way the I could have an if statement that checks if the current position in the array is equal to the next, like this:

for(int i = 0; i < 3; i++)
{
    for(int j = 0; j < 5; j++)
    {
        nums[i][j] = 1 + (int)(Math.random() * 60);
        for(int l = 1; l < 3; l++){
            for(int m = 1; m < 5; m++){
                if(nums[i][j] == nums[l][m]){
                    nums[i][j] = 1 + (int)(Math.random() * 60);
                }
            }
        }

As you can see here I have added l and m which both have a number 1, which will put them one above the previous position. Also my if statement checks if the values are same, and if they are, it randoms the numbers again.

This is not working for me, could someone give me a hand please, what am I doing wrong ?

nbrooks
  • 18,126
  • 5
  • 54
  • 66
arjwolf
  • 181
  • 4
  • 16
  • *"...my if statement checks if the values are same, and if they are, it randoms the numbers again."* - and what if this random number is another duplicate? Also, why do you have `1 +`? – RaminS Oct 21 '16 at 23:48

6 Answers6

0

You can do this

 Stack<Integer> stack = new Stack<>();
    for(int i=1;i<61;i++){
        stack.add(i)
    }

    Collections.shuffle(stack);

    for(int i = 0; i < 3; i++){
        for(int j = 0; j < 5; j++){
            nums[i][j] = stack.pop();
        }
    }
  1. Fill up a List from 1 - 60
  2. Use Collections.shuffle(List) to shuffle the numbers
  3. Get the numbers from the shuffled

In this case, I used a Stack.

Take a look at this post. Generating Unique Random Numbers in Java

Community
  • 1
  • 1
Aloyweesious
  • 41
  • 1
  • 6
  • Include the essential parts of the answer in your post; do not merely redirect to another page. If you feel that the question is a duplicate, flag it as such. – RaminS Oct 21 '16 at 23:53
  • Nice answer. Quick note: In Java the `Stack` class isn't recommended for use anymore. The [documentation](http://docs.oracle.com/javase/7/docs/api/java/util/Stack.html) for `Stack` even suggests using `Deque` instead. See [this post](http://stackoverflow.com/q/12524826/803925) for more details on reasoning. – nbrooks Oct 22 '16 at 00:34
  • Also [`Collections.shuffle`](http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#shuffle(java.util.List)) only works on values of type `List`... – nbrooks Oct 22 '16 at 00:43
0

You can simply use a Set to keep track of the numbers that you have already seen, and define a new function to encapsulate your "generate unique random number" logic. That will end up being a lot easier than trying to check the 2D array for the values each time you generate one. The nested loops are confusing, for starters, but the Set is also preferable because it has constant (i.e. O(1)) lookup time, so it finds values quickly.

private final Set<Integer> usedValues = new HashSet<>();

private void populateArray(int[][] nums) {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 5; j++) {
            nums[i][j] = getUniqueRandomNum();
        }
    }
}

private int getUniqueRandomNum() {
    int val;

    do {
        val = 1 + (int) (Math.random() * 60);
    } while (usedValues.contains(val));

    usedValues.add(val);

    return val;
}
nbrooks
  • 18,126
  • 5
  • 54
  • 66
  • You could also use `while (!usedValues.add(val))`. – Tom Oct 22 '16 at 00:01
  • @Tom Yep that's true, and it's one fewer statement, but that seems less readable to me. I prefer it to be explicit: loop while the set `contains` this value, and afterwards `add` this value to the set. That makes it super obvious what's happening the next time you read it, and for anyone else who reads it. Could be personal preference though. – nbrooks Oct 22 '16 at 00:03
0

store your numbers in an array and remove the ones that you already have used

    LinkedList<Integer> integers = new LinkedList<Integer>();
    for (int i = 0; i < 60; i++) {
        integers.add(i);
    }
    for(int i = 0; i < 3; i++)
    {
        for(int j = 0; j < 5; j++)
        {
            int random = 1 + (int)(Math.random() * integers.size());
            nums[i][j] = integers.remove(random);
        }
    } 
David Florez
  • 1,460
  • 2
  • 13
  • 26
0

Try this

public static int[][] random(int i, int j, int max) { // 3, 5, 60
    Supplier<Integer> function = new Supplier<Integer>() {
        final Set<Integer> ints = new HashSet<>();
        final Random r = new Random();
        @Override
        public Integer get() {
            int n;
            while (ints.contains(n = r.nextInt(max)))
                ;
            ints.add(n);
            return n;
        }
    };
    int[][] matrix = new int[i][j];
    IntStream.range(0, i * j).forEach(in -> matrix[in % i][in % j] = function.get());
    return matrix;
}

or simply using ThreadLocalRandom

public static int[][] random(int i, int j, int max) {
    List<Integer> random = ThreadLocalRandom.current().ints(0, max).distinct().limit(i * j).collect(ArrayList::new, List::add, List::addAll);
    int[][] matrix = new int[i][j];
    IntStream.range(0, i * j).forEach(in -> matrix[in % i][in % j] = random.get(in));
    return matrix;
}
Saravana
  • 12,647
  • 2
  • 39
  • 57
-1

You dont need to remove "them one above the previous position", you have to create another loop that checks if the new Math.ramdom() equals an element of the array.

I will show you with code:

for(int i = 0; i < 3; i++)
        {
            for(int j = 0; j < 5; j++)
            {
                int numRam = (int)(Math.random() * 60);
                bool check = true;
                for(int l = 1; l < (Size of the array); l++){
                    if(nums[i][l] == numRam){
                         check = false;
                         break;
                    }
                }

                if(!check){         //If the number exist you do j - 1
                    j--;            //so you would try with a different ramdom number
                }else{
                    nums[i][j] = numRam;
                }
             }
        }
Mike Szer
  • 42
  • 1
  • 11
-1

You could also try this:

int end = arr.length;
Set<Integer> set = new HashSet<Integer>();

for(int i = 0; i < end; i++){
    set.add(arr[i]);
}

That right there is a fix I found, I'm not sure if it will work with your code, but it's something to try.

Class HashSet

boolean add(E e)

Adds the specified element to this set if it is not already present.

Community
  • 1
  • 1