Generate even and odd random numbers with defined quantities

Asked

Viewed 2,479 times

1

How to generate random numbers with Random and limiting the number of odd and odd pairs?

Example: 50 numbers should be generated in total, being 20 pairs and 30 odd.

public int GeraVetorParImpar() {
    contPar = 0;
    contImpar = 0;
    int x = 0;

    while (contPar <= 5 | contImpar <= 5) {
        for (int i = 0; i < vetor.length; i++) {
            x = (random.nextInt(vetor.length) + 1);

            if (vetor[i] % 2 == 0) {
                vetor[i] = x;
                contPar++;
            } else {
                if (vetor[i] % 2 != 0) {
                    vetor[i] = x;
                    contImpar++;
                }

            }
        }
    }

    System.out.println("Valor do vetor principal:");
    for (int k = 0; k < vetor.length; k++) {
        System.out.println(vetor[k]);
    }
    System.out.println("Total Par: " + contPar);
    System.out.println("Total Impar: " + contImpar);

    return 0;
}
  • Welcome, edit your question and put the code you have, even if it has errors.

  • Some observations, which are not directly related to your question but may be disturbing: 1) the "or logical" operator is composed of two vertical bars ||, whereas the "or bit" operator is composed only of a vertical bar |, read more, 2) the counterpoint of x % 2 == 0 is necessarily, x % 2 != 0, and that goes for any boolean comparison expression, since the "different" operator is the same as "not equal", so do if (vetor[i] % 2 == 0) { ... } else if (vetor[i] % 2 != 0) { ... makes the second if redundant

    1. the comparison of if is being made on the vector, not on x; as the value of the vector being filled, I believe it had not been filled previously, is that right? would be comparing with potentially "junk" values? 4) what is the purpose of while before the for? as iterated over the positions of the vector, if by chance the vector has at least 9 positions (2 * 5 - 1), then guaranteed the while will not fire, as at least 5 numbers, even or odd will have been generated

1 answer

2

The question leaves some criteria open, so let’s see some possible approaches.

It was not said, for example, the value limits. Can it be any valid integer number? In Java, a int can go from -2147483648 to 2147483647. The program can accept any number in this range, can only be positive, there is a minimum or maximum limit?

Assuming there are no such limits, you could have a method that creates an array with a certain amount of numbers that meet a certain criterion (in this case, be even or odd):

// ** Atenção: este algoritmo não verifica números repetidos **
public int[] gerarNumeros(int quantidade, boolean par) {
    Random r = new Random();
    int[] numeros = new int[quantidade];
    int i = 0;
    int resto = par ? 0 : 1;
    while (i < quantidade) {
        do {
            numeros[i] = r.nextInt();
        } while (Math.abs(numeros[i]) % 2 != resto);
        // abs() para casos em que o número é negativo, pois -3 % 2 == -1
        i++;
    }

    return numeros;
}

This method receives the amount of numbers to be created, and a boolean whether I want even numbers or not (if it’s even true, generates even numbers if it is false, generates odd).

Then I make a loop to generate the amount of numbers I need. Inside this while there is a do/while to generate the number until it meets the criterion (be even or odd, according to the boolean). In checking the rest of the division by 2, I use Math.abs to deal with cases of negative numbers, since -3 % 2 results in -1 (see). Using abs, the account would become 3 % 2, resulting in 1.

The problem of loop do/while is that it can rotate several times until it finds a number that meets the criteria. In that case, we could exchange it for a if:

// em vez do do {  ...  } while, use um if
if (Math.abs(numeros[i]) % 2 != resto) {
    numeros[i] += 1;
}

So, if the criterion is even and the number is odd (or vice versa), just add 1. Now just generate the numbers and join everything in a single array:

int[] pares = gerarNumeros(20, true);
int[] impares = gerarNumeros(30, false);
int[] numeros = new int[50];
for (int i = 0; i < 20; i++) {
    numeros[i] = pares[i];
}
for (int i = 0; i < 30; i++) {
    numeros[i + 20] = impares[i];
}

Or, if you prefer, you can use System.arrayCopy instead of two ties for:

System.arraycopy(pares, 0, numeros, 0, pares.length);
System.arraycopy(impares, 0, numeros, pares.length, impares.length);

Thus, the array numeros will have 20 even numbers and 30 odd numbers, all generated randomly.

This solution puts all the pairs at the beginning (in the first 20 positions), and then the odd ones. If you want them to be in random order, you can shuffle the array (see below). And if you want to limit number values, you can use r.nextInt(limiteMaximo) instead of only r.nextInt() (that will generate a number between zero and limiteMaximo - 1).


Do not allow repeated numbers

But as indicated in the comments, this solution does not check repeated numbers. In this case, you would have to use a java.util.Set:

public Set<Integer> gerarNumerosSemRepeticao(int quantidade, boolean par) {
    Random r = new Random();
    Set<Integer> numeros = new HashSet<>();
    int resto = par ? 0 : 1;
    while (numeros.size() < quantidade) {
        int numero = r.nextInt();
        if (Math.abs(numero) % 2 != resto) {
            numero++;
        }
        if (!numeros.contains(numero)) {
            numeros.add(numero);
        }
    }

    return numeros;
}

The Set does not allow repeated elements. The detail is that Java collections do not allow primitive types (such as int), so I have to use a Set of Integer.

Basically, if the generated number is not in the Set, i add. But if it is, it does nothing and continues the loop.

From there, just generate the numbers and copy them to an array:

// gerar os pares
Set<Integer> numeros = gerarNumerosSemRepeticao(20, true);
// gerar os ímpares e já adiciona no Set
numeros.addAll(gerarNumerosSemRepeticao(30, false));

int[] array = new int[numeros.size()];
int i = 0;
for (Integer num : numeros) {
    array[i] = num;
    i++;
}

If using Java >= 8, you can use streams to generate the array:

int[] array = numeros.stream().mapToInt(Integer::intValue).toArray();

Another feature of Set (besides not allowing repeated numbers) there is no guarantee as to the order of the elements (not necessarily in the same order in which they were inserted), so the resulting array will probably not have the pairs at the beginning and then the odd ones.


Another approach

Another alternative is to have arrays with predefined numbers. For example, I can generate two arrays, with the first 1000 even and odd numbers:

int[] pares = new int[1000];
int[] impares = new int[1000];
for (int i = 0; i < 1000; i++) {
    pares[i] = 2 * i;
    impares[i] = pares[i] + 1;
}

In this case, I have the even numbers between zero and 1998, and the odd numbers between 1 and 1999.

Now just shuffle these arrays and grab the first N elements of each one. To shuffle, you can use the Fisher-Yates scrambling algorithm:

public void embaralha(int arr[]) {
    Random r = new Random();

    for (int i = arr.length - 1; i > 0; i--) {
        int j = r.nextInt(i + 1);

        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

Then shuffle the odd and even arrays, and take the amount you need from each one:

embaralha(pares);
embaralha(impares);

int[] numeros = new int[50];
// copia somente 20 pares
System.arraycopy(pares, 0, numeros, 0, 20);
// copia somente 30 ímpares
System.arraycopy(impares, 0, numeros, 20, 30);

This solution, just like the previous one, also puts all the pairs at the beginning, and then the odd ones. But you could shuffle the result using embaralha(numeros), if you want (the question does not make clear the order in which the numbers should be).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.