2

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".

Wasabi Thumbs
  • 303
  • 1
  • 2
  • 8
  • To avoid O(n) you can use a HashMap for looking up existing nicknames. Then if you want a gapless sequence you must keep a reference to the latest sequence number as well as the holes in the sequence. Fill holes first then increase the gapless sequence. What problem are you really trying to solve though? – plalx Jun 25 '21 at 19:39

1 Answers1

1

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.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • Instead of `get+put` one can also use `merge` but I avoided complicated things, and `merge` is also less understandable to beginners reading stackoverflow. – Joop Eggen Jun 25 '21 at 20:04