3

I am generating 4 character pin numbers for children to use in schools. The pins have to be stored as 4 character strings in a database. This is the method I am using to generate the pins:

public void generatePin() {
    String pin;
    Random r = new Random();
    for (int i = 0; i < createdStudents.size(); i++) {
        int rand = r.nextInt((3998 - 1) + 1) + 1;
        if (rand < 10) {
            pin = "000" + rand;
        } else if (rand < 100) {
            pin = "00" + rand;
        } else if (rand < 1000) {
            pin = "0" + rand;
        } else {
            pin = "" + rand;
        }
        createdStudents.get(i).setPin(pin);
    }
}

My question is:

If I slightly alter the above method, adding each pin to an ArrayList of String type as I go, what is the most efficient way to 'search' through that List and make sure that 2 students in the one school don't end up with the same pin?

(Note: there will never be more than 1,200 students per school)

Edit:

I ended up doing the following:

public void generatePin() {
    List<String> pins = new ArrayList<String>();
    String pin;
    Random r = new Random();
    for (int i = 0; i < createdStudents.size(); i++) {
        int rand = r.nextInt((9999 - 1) + 1) + 1;
        if (rand < 10) {
            pin = "000" + rand;
        } else if (rand < 100) {
            pin = "00" + rand;
        } else if (rand < 1000) {
            pin = "0" + rand;
        } else {
            pin = "" + rand;
        }

        if (!pins.contains(pin)) {
            createdStudents.get(i).setPin(pin);
            pins.add(pin);
        } else {
            i--;
        }
    }
}

Creating an ArrayList to store the pins, checking if the pin exists in the ArrayList after each generation. If it doesn't, assign it to a student. If it does, decrement the loop counter in order to go back to the just referenced index in the list and generate a new pin. This will continue until a unique pin is generated, where it will be assigned to a student.

3 Answers3

6

Use a Set, since it will not allow duplicates, to remember and check for used pins. I moved the code for generating the code into a separate method

public void generatePin() {
    String pin;
    Set<String> generatedPins = new HashSet<>();
    for (int i = 0; i < createdStudents.size(); i++) {
        do {
            pin = generatePinCode();
        } while (!generatedPins.add(pin));
        createdStudents.get(i).setPin(pin);
    }
}
Joakim Danielson
  • 29,280
  • 4
  • 14
  • 35
  • Set is used when you don't want duplicates in your collection because it doesn't admit duplicates, then this is the right way to do it. – IgrewupwithSlackware Aug 24 '18 at 08:38
  • I hope I don't misunderstood your comment but yes the reason I am using a set is because it doesn't allow duplicates – Joakim Danielson Aug 24 '18 at 08:46
  • 2
    Exactly, I was suggesting to explain why to use a Set instead of a List; I see that you added "since it will not allow duplicates", then I think that now the answer is well explained :) – IgrewupwithSlackware Aug 24 '18 at 09:07
0

First, I would do the generation of pins, then set them to each student. Using Set and SecureRandom with a strong algorithm (pins are sensitive data I suppose ...). Like :

    int studentsNumber = 4;

    // Securely generate N unique pins
    Set<String> pins = new HashSet();
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    while (pins.size() != studentsNumber) {
        int pin = sr.nextInt((3998 - 1) + 1) + 1;
        String pinStr = String.format("%04d", pin);
        pins.add(pinStr);
    }

    // Set pins to the students
    for (Student s : createdStudents) {
        for (String pin : pins) {
            s.setPin(pin);
        }
    }
cactuschibre
  • 1,149
  • 1
  • 14
  • 27
0

Code for pin generation (No change):

public String generatePin() {
    String pin;
    Random r = new Random();
    int rand = r.nextInt((3998 - 1) + 1) + 1;
    if (rand < 10) {
        pin = "000" + rand;
    } else if (rand < 100) {
        pin = "00" + rand;
    } else if (rand < 1000) {
        pin = "0" + rand;
    } else {
        pin = "" + rand;
    }

    return pin;
}

Make sure distributed pins are unique:

public void distributeUniquePins() {
    List<String> distributedPins = new ArrayList<>();

    createdStudents.forEach(student -> {
        String pin = generatePin();

        while(distributedPins.contains(pin)) {
            pin = generatePin();
        }

        distributedPins.add(pin);
        student.setPin(pin);
    });
}
Minar Mahmud
  • 2,289
  • 6
  • 18
  • 29