'How can I fix my code that's supposed to give me an array of random integers?

So I started a method which is supposed to give me an array filled with random non repeating values, that additionally are odd. However, I only get the array filled with somewhat wrong values:

public static int[] Array(int n, int max) {
  int [] arr = new int [n];
  int newnum;
  Random rn = new Random();

  for(int i = 0; i < arr.length; i++){
    newnum = rn.nextInt(0,max);
    for(int j = 0; j < i; j++){
      while(newnum == arr[j] && newnum % 2 == 0){
         newnum = rn.nextInt(0, max);
        }
      }
   arr[i] = newnum;
    }
return arr;
}


Solution 1:[1]

The issue here is this:

  • You go through all the numbers already in the list and you reroll your number if it's equal to j. However, once you have done the comparison, your new number could be equal to arr[j-1], you don't re-check. You need to start over every time there is a match.
  • It should be || and not && in your condition. You want to reroll if the number is equal to a previous number OR if it is even.

The optimisation also is terrible but I guess that's not what you asked.

Fixed version (but not optimized):

public static int[] array(int n, int max) {
  int[] arr = new int[n];
  int newnum;
  Random rn = new Random();

  for (int i = 0; i < arr.length; i++) {
    newnum = rn.nextInt(max);
    for (int j = 0; j < i; j++) {
      if (newnum == arr[j] || newnum % 2 == 0) { 
        //or instead of and
        //we are also using if here
        //because we are already re-running the loop by starting over from j = 0
        newnum = rn.nextInt(max);
        j = 0;
      }
    }
    arr[i] = newnum;
  }
  return arr;
}

There are much better ways to do this using java features but I imagine you are still in school and they didn't teach them yet.

Solution 2:[2]

You should make sure that you lay your code out so that you understand it.

You should make sure that your conditions are correct at all times, and don't hesitate to delegate complexity to other methods.

public static int[] array(int n, int max) {
  int[] arr = new int[n];
  Random rn = new Random();

  for (int i = 0; i < arr.length; i++) {
    int candidate = rn.nextInt(max);
    while (candidate % 2 == 0 || isContainedIn(candidate, arr, i - 1)) {
      candidate = rn.nextInt(max);
    }
    arr[i] = candidate;
  }
  return arr;
}
private static boolean isContainedIn(int candidate, int[] arr, int index) {
  for (int i = 0; i <= index; i++) {
    if (arr[i] == candidate) {
      return true;
    }
  }
  return false;
}

An alternative is to use streams:

public static int[] array(int n, int max) {
  max /= 2; // Divide by two to avoid generating twice the expected numbers.
  if (n > max) throw new IllegalArgumentException("Impossible to generate such an array");
  int[] array = new Random().ints(0, max) // Generate ints between 0 and half max
    .map(i -> i * 2 + 1)                  // Make sure they're odds
    .distinct()                           // Make sure they don't repeat
    .limit(n)                             // Take n of those numbers
    .toArray();                           // Put them in an array
  return array;
}

Solution 3:[3]

Why not create a set and keep adding till you have n elements?

Solution 4:[4]

You want non-repeating odd numbers in a range. For non-repeating numbers you are better off using a shuffle for a small range or a set for a large range.

For picking odd numbers it might be easier to pick integers from half the range and use num = 2 * pick + 1 so as to not generate any even numbers, though you will need to be careful about setting the correct range of integers for the initial pick.

Solution 5:[5]

As Janardhan Maithil suggested you could utilize a set for the destinctveness

But you also have to take into account what should happen if one would try to get more values, than are available.

public static int[] randomDistinctiveOdds(int maxAmount, int maxValue) {
    if (maxAmount / 2 > maxValue) {
        throw new IllegalArgumentException("Not enough distinct odd values in the range from 0 to " + maxValue);
    }

    Random random = new Random();
    Set<Integer> result = new HashSet<>(maxAmount);

    int nextInt;
    while (result.size() < maxAmount) {
        if ((nextInt = random.nextInt(maxValue)) % 2 == 1)
            result.add(nextInt);
    }

    return result.stream().mapToInt(Integer::intValue).toArray();
}

or a solution with streams

public static int[] randomDistinctiveOddsWithStreams(int maxAmount, int maxValue) {
    if (maxAmount / 2 > maxValue) {
        throw new IllegalArgumentException("Not enough distinct odd values in the range from 0 to " + maxValue);
    }

    List<Integer> odds = IntStream.range(0, maxValue)
            .boxed()
            .filter(i -> i % 2 == 1) // only odds
            .collect(Collectors.toList());

    Collections.shuffle(odds);

    return odds.stream()
            .mapToInt(Integer::intValue)
            .limit(maxAmount) // take at most maxAmount
            .toArray();
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Janardhan Maithil
Solution 4 rossum
Solution 5 Valerij Dobler