使用Java Faker生成唯一的随机邮政编码

3

我正在使用Java Faker,希望生成一系列唯一的随机邮政编码。Python和Ruby支持unique关键字,但我无法理解如何在Java中使其工作。这个特性受支持吗?

以下是Java代码:

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

Python示例

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

Ruby示例

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

3

使用Stream.generate()是生成值的好方法。要使用它,请定义一个Supplier lambda,该lambda将提供源值。在这种情况下,是邮政编码。

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

使用 distinct() 使值唯一。
var zipCodesStream = Stream.generate(() -> faker.address().zipCode())
        .distinct();

使用limit可以获取任意数量的值。

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

一定要使用 limit,否则它永远不会停止收集。还要注意,如果源没有足够的不同值,那么该过程将挂起!

对于更加强大的实现,请参见 Kotlin 的 Sequences


完整的 (jdk11) 示例:

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");
  }

}

输出:

Generated 10000 distinct zip codes in 387ms

1
非常优雅的解决方案!我更喜欢使用内置库而不是自定义方法。我正在开发的功能已经完成,但是等我有时间时,我会重新审视并采用这个解决方案。如果一切顺利,我会修改答案。谢谢! - DV82XL

2

通过查看您提供的源代码,可以发现Java实现不支持unique,因此您需要自己维护。使用java.util.Set<String>非常容易:

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

这可能比本地实现慢一些 - 或者不会 - 但它将提供你所需要的内容。

感谢您的快速回答!只要唯一邮政编码列表相对较快地收敛(或完全收敛),此解决方案就可以工作,否则我还需要实现类似于UniquenessException(Python)或RetryLimitExceeded(Ruby)的等效功能,这应该不难。 - DV82XL
1
@当然。我不知道你需要多少个唯一的邮政编码。如果它足够大,你可以考虑完全不同的实现方式。 - Aleks G
很好的观点,我从来没有具体说明。我需要1k-10k范围内的东西,所以这不应该是一个问题,因为有些生成的邮政编码使用ZIP+4格式,会导致更大的数量池,从而减少冲突。 - DV82XL

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接