Generate unique random zip codes with Java Faker

Viewed 1175

I'm using Java Faker and would like to generate a sequence of unique random zip codes. Python and Ruby support the unique keyword. but I can't figure out how to make this work in Java. Is this feature supported?

Here's the Java code:

// Not guaranteed to be unique
String zipCode = faker.address().zipCode()

Python example:

import faker
fake = faker.Faker()
number = fake.unique.random_int()

Ruby example:

# This will return a unique name every time it is called
Faker::Name.unique.name
2 Answers

Looking through the source code (that you linked to), it looks like unique is not supported by Java implementation, so you'll need to maintain that yourself. It's very easy with java.util.Set<String>:

Set<String> zipCodes = new Set<>();
...
String zipCode;
do {
    zipCode = faker.address().zipCode();
} while (zipCodes.contains(zipCode));
zipCodes.add(zipCode);
...

This may be slower than native implementation - or not - but it'll give you what you need.

Using Stream.generate() is a great way to generate values. To use it, define a Supplier lambda that will provide the source values. In this case, zip codes.

var zipCodesStream = Stream.generate(() -> faker.address().zipCode());

Use distinct() to make the values unique.

var zipCodesStream = Stream.generate(() -> faker.address().zipCode())
        .distinct();

Any number of values can be grabbed using limit.

var zipCodes = zipCodesStream
    .limit(10_000)
    .collect(Collectors.toList());

Make sure to use limit, or it will never stop collecting. Also be aware that if the source doesn't have enough distinct values then the process will hang!

For an even more powerful implementation, see Kotlin's Sequences.


Full (jdk11) example:

import com.github.javafaker.Faker;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.stream.Stream;

class scratch {
  
  public static void main(String[] args) {

    // use a Thread local random, just in case we're multi-threading
    var random = ThreadLocalRandom.current();
    // use the random in the Faker, for consistency
    var faker = Faker.instance(random);

    // generate a Stream - the source values are from Faker
    var zipCodesStream =
        Stream.generate(() -> faker.address().zipCode())
            // make the generated values are distinct
            .distinct();

    var startMillis = System.currentTimeMillis();

    // grab 10k values, put them into a list
    var zipCodes = zipCodesStream
        .limit(10_000)
        .collect(Collectors.toList());
    var elapsedMillis = System.currentTimeMillis() - startMillis;

    // verify the generated values are distinct
    assert zipCodes.size() == Set.copyOf(zipCodes).size()
        : "Expect zipCodes has no duplicates";

    System.out.println("Generated " + zipCodes.size() + " distinct zip codes in "
        + elapsedMillis + "ms");
  }

}

Output:

Generated 10000 distinct zip codes in 387ms
Related