A good way to prevent string repeats in java without O(n) operations in Java?

Viewed 46

Here's a hypothetical situation: you want to automatically assign unique nicknames to unique names, with no repeats. Since nicknames contain less text information than the original name, as that is the nature of nicknames, it's not guaranteed that two names that are unique from eachother will also produce unique nicknames. To solve this, I want to tack a number onto the end that is guaranteed to make the nickname unique. However, I feel like my naive approach is kind of terrible, and I would like to learn how someone who knows what they are doing would go about this.

private static final List<String> nicknames = new ArrayList<String>();
// ...
String fullName = "a cool test name";
String base = getNickname(fullName); // -> "ACTN"
String nick = base;
int numAdd = 0;
Predicate<String> within = ((String s) -> {
    for (String os : nicknames) {
        if (os.equalsIgnoreCase(s)) return true;
    }
    return false;
});
while (within.test(nick)) {
    numAdd++;
    nick = base + numAdd;
}
// nick is now a unique string

Personally, I hate while loops and I feel a little dumb for not being able to think of a solution myself. Maybe store strings that start with the base and then some numbers, and find the maximum number of those and add 1 to it? That sounds like it would take a lot of memory, and then if for instance there was "ACTN3, ACTN4, ACTN5" and then "ACTN4" was deleted, a new prefix would wrongly be assigned "ACTN6".

1 Answers

Store the nickname in lowercase in a map with as value the next free number, or 0 when no number suffix added.

Map<String, Integer> nicknames = new HashMap<>();
String base = getNickName();

// String trailing number:
String realBase = base.replaceFirst("(^.*?)\\d+$", "$1");

realBase = realBase.toLowerCase(Locale.US);
int suffix = nicknames.getOrDefault(realBase, 0);
nickNames.put(realBase, suffix + 1);
String nickname = realBase;
if (suffix != 0) {
    realBase = realBase + suffix;
}

The above strips digits at the end of the original nickname. So does not allow to pick february29.

Related