问题
Currently my program (see below) generates random strings (made of numbers) from 8 - 12 characters in length.
public static string GenerateNewCode(int CodeLength)
{
string newCode = String.Empty;
int seed = unchecked(DateTime.Now.Ticks.GetHashCode());
Random random = new Random(seed);
// keep going until we find a unique code `
do
{
newCode = random.Next(Convert.ToInt32(Math.Pow(10, CodeLength - 1)), Convert.ToInt32(Math.Pow(10, CodeLength) - 1)).ToString("0000");
}
while (!ConsumerCode.isUnique(newCode));
// return
return newCode;
}
However, their is a problem with the method, when the codeLength
is 10 or greater it causes error because 109 is greater than int32.MaxValue
.
Not sure how to get around this issue.
回答1:
Your code doing the same thing without some freak lines:
public static string GenerateNewCode(int CodeLength)
{
Random random = new Random();
StringBuilder output = new StringBuilder();
do
{
for (int i = 0; i < CodeLength; i++)
{
output.Append(random.Next(0, 10));
}
}
while (!ConsumerCode.isUnique(output.ToString()));
return output.ToString();
}
回答2:
Rather than generating a number from 0 to 10n-1 and then converting it to string, generate n numbers from 0 to 9, convert each one to a string, and concatenate them together.
I note that this technique yields numbers in the range (say for n = 4) 0 to 9999; your original version yielded numbers from 1000 to 9999. You could generate the first digit from 1 to 9 instead of 0 to 9 if you wanted to preserve that property.
Surely the way I am doing it is more random then 'n' concatenated 0 - 9 values.
Please explain why you believe that. I am fascinated to learn why people believe falsehoods.
Could you not create a Guid.NewGuid().Tostring() and truncate the most significant characters to get a random string of length N?
You could but you should not. GUIDs are not guaranteed to be random and no proper subset of the bits of a GUID is guaranteed to be unique. Taking bits out of a GUID and expecting the bits to have the properties of a GUID is like taking the rudder off a plane and expecting the rudder to fly. Never ever ever do that.
Rather, use tools for the purpose they were designed for. GUIDs were designed to provide globally unique identifiers, so use them for nothing else.
A question you did not ask but probably should:
What else is wrong or suspicious with my code?
int seed = unchecked(DateTime.Now.Ticks.GetHashCode());
What on earth is that code doing? First off, the random class already uses the current time as a seed; this is unnecessary. Second, what on earth is the purpose of an "unchecked arithmetic" expression that contains no arithmetic? Third, why would you get the hash code? You are not balancing a hash table!
Random random = new Random(seed);
If this method is called twice in the same tick then the seed will be the same, and therefore the sequence of random numbers will be the same, which means that you will potentially wait a long time because every generated number will be a collision in your 'unique' set.
A better technique is to make a static instance of Random, seeded once. If your program is single-threaded then that's no problem. If it is multi-threaded, make sure you don't access the Random from multiple threads; it is not thread safe and its thread safety violation failure mode is not good.
newCode = random.Next(Convert.ToInt32(Math.Pow(10, CodeLength - 1)), Convert.ToInt32(Math.Pow(10, CodeLength) -
Is it really necessary to work out the power twice per loop, when it is exactly the same every time? Work it out once before the loop begins. The code will be shorter, clearer and faster.
while (!ConsumerCode.isUnique(newCode));
If the collection is full, this loops forever. If the collection is almost full then this loops for a long time. This is a potentially bad technique for generating unique random numbers in a range. Only do this if you know ahead of time that the number of possibly generated numbers is far, far larger than the maximum size of the collection.
So what would your method look like for this functionality?
I would be inclined to do something like this. First, I'd like an infinite supply of digits:
// Yield an infinite sequence of pseudo-random digits 0-9
// This method is not thread-safe.
private static Random random = new Random();
static IEnumerable<int> Digits()
{
while(true)
yield return random.Next(0, 10);
}
Now I can generate a unique string of digits:
// Generates a random code of given length. If it is not
// in the set, adds it and returns the code. If it is
// already in the set, tries again.
static string AddUniqueCode(int length, HashSet<string> set)
{
while(true)
{
string code = string.Join(null, Digits().Take(length));
if (set.Add(code))
return code;
}
}
I like my methods short.
You could also make the Digits method use crypto-strength randomness instead of pseudo-randomness if unpredictability is important to you. pseudo-random numbers are easy to predict.
回答3:
Generate a random number from 0 to 9; add '0' to it; cast it to a char; now you have a random digit. Repeat for as many digits as you need.
Like this: char c = (char)(random.Next(10) + '0');
回答4:
One method you could use Random.NextDouble() to return a number between 0..1, then scale it to 0..26 and use a lookup table to return an alphabetic character based on the index. For example:
char lookup = new char[] { 'a', 'b', 'c' ... 'z' }; // ensure length 26
int index = (int)(random.NextDouble() * 25.0);
return lookup[index]
A more efficient method would involve using the ascii table to convert an integer to the desired alphanumeric character.
Best regards,
回答5:
You can create two random numbers where the first random number has a length of 6-10 and the second random number has a length of 2. After the two numbers are generated, combine them to make a string that has a length of 8-12.
Example:
public static string GenerateNewCode(int CodeLength)
{
string newCode = String.Empty;
int seed = unchecked(DateTime.Now.Ticks.GetHashCode());
Random random = new Random(seed);
// keep going until we find a unique code `
do
{
// The firstPart int will be a random number that has a length of 6, 7, 8, ,9, or 10 digits
int firstPart = random.Next(100000,2147483647);
// The secondPart int will be a random number that has a length of two digits
int secondPart = random.Next(10,99);
// Concatenate firstPart and secondPart. This will create a string that has a length of 8, 9, 10, 11, or 12 chars.
newCode = firstPart.ToString() + secondPart.ToString();
}
while (!ConsumerCode.isUnique(newCode));
// return
return newCode;
}
来源:https://stackoverflow.com/questions/8730511/random-number-generator-variable-length