Skip to content

Instantly share code, notes, and snippets.

@idea-lei
Last active July 9, 2025 10:16
Show Gist options
  • Save idea-lei/8b619c1b46ed2158c2920a172a644c7f to your computer and use it in GitHub Desktop.
Save idea-lei/8b619c1b46ed2158c2920a172a644c7f to your computer and use it in GitHub Desktop.
High performance Short Id
/// <summary>
/// ShortId in string format, preferred when a GUID is overkill.
/// </summary>
public static class ShortId
{
/// <summary>
/// 32 chars (2^5). removed some chars for better readablity (i,l,o,u)
/// </summary>
private const string _chars = "0123456789abcdefghjkmnpqrstvwxyz";
// If the probability of success is 50%, the probability of success in five attempts is 97%.
private const byte _maxTrialTimes = 5;
/// <summary>
/// Generates a short id. May be duplicated.
/// </summary>
/// <remarks>
/// Based on long type (64-1=63 bit due to sign), so max length is 12 (13*5=65), not recommanded for fewer than 6 chars.
/// </remarks>
/// <param name="size">
/// Length of the result string. Range 6-12, 10 as default. <br/>
/// Default value 10 will contain 32^10 (around 10^15) possibilities <br/>
/// When generating 10^6 times, it will have about 1.4% chance to have duplicate elements.
/// </param>
public static string New([Range(6, 12)] byte size = 10)
{
// max: 3FFF FFFF (62 bit), half of the long.MaxValue, but still enough for size 12
long value = (long)Random.Shared.Next(int.MaxValue) * Random.Shared.Next(int.MaxValue);
var output = new char[size];
for (int i = size - 1; i >= 0; i--)
{
output[i] = _chars[(int)(value % 32)];
value >>= 5;
}
return new string(output);
}
/// <summary>
/// Generates a unique short id that is different from the existing items.
/// </summary>
public static string New(IQueryable<string> existingIds, [Range(6, 12)] byte size = 10)
{
existingIds = existingIds.Where(x => x.Length == size);
byte count = 0;
string newId = New(size);
while(existingIds.Contains(newId))
{
newId = New(size);
count++;
if (count > _maxTrialTimes)
throw new Exception("Too many elements in the collection to find an unique id.");
}
return newId;
}
/// <summary>
/// Generates a unique short id that is different from the existing items.
/// </summary>
public static string New(IEnumerable<string> existingIds, [Range(6, 12)] byte size = 10)
{
existingIds = existingIds.Where(x => x.Length == size);
byte count = 0;
string newId = New(size);
while (existingIds.Contains(newId))
{
newId = New(size);
count++;
if (count > _maxTrialTimes)
throw new Exception("Too many elements in the collection to find an unique id.");
}
return newId;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment