简体   繁体   English

随机数发生器 - 可变长度

[英]Random number generator - variable length

Currently my program (see below) generates random strings (made of numbers) from 8 - 12 characters in length. 目前我的程序(见下文)生成长度为8-12个字符的随机字符串(由数字组成)。

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 10 9 is greater than int32.MaxValue . 但是,它们是该方法的问题,当codeLength为10或更大时,它会导致错误,因为10 9大于int32.MaxValue

Not sure how to get around this issue. 不知道如何解决这个问题。

Rather than generating a number from 0 to 10 n -1 and then converting it to string, generate n numbers from 0 to 9, convert each one to a string, and concatenate them together. 而不是生成从0到10 n -1的数字然后将其转换为字符串,生成从0到9的n个数字,将每个数字转换为字符串,并将它们连接在一起。

I note that this technique yields numbers in the range (say for n = 4) 0 to 9999; 我注意到这种技术产生的范围内的数字(比如n = 4)0到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. 您的原始版本产生的数字从1000到9999.如果您想要保留该属性,则可以生成从1到9而不是0到9的第一个数字。

Surely the way I am doing it is more random then 'n' concatenated 0 - 9 values. 当然,我这样做的方式更随机,然后'n'连接0 - 9值。

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? 你能不能创建一个Guid.NewGuid()。Tostring()并截断最重要的字符来获得一个长度为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. GUID不保证是随机的,并且GUID的任何比特子集都不保证是唯一的。 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. 从GUID中取出位并期望这些位具有GUID的属性就像将舵从飞机上取下并期望方向舵飞行一样。 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. GUID旨在提供全局唯一标识符,因此无需使用它们。

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. 如果在同一个tick中调用此方法两次,那么种子将是相同的,因此随机数的序列将是相同的,这意味着您可能会等待很长时间,因为每个生成的数字都将是您的碰撞'独特'集。

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; 如果它是多线程的,请确保您不从多个线程访问Random; 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. 如果不可预测性对您很重要,您还可以使Digits方法使用加密强度随机性而不是伪随机性。 pseudo-random numbers are easy to predict. 伪随机数很容易预测。

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

Generate a random number from 0 to 9; 生成0到9之间的随机数; add '0' to it; 添加'0'; 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'); 像这样: char c = (char)(random.Next(10) + '0');

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. 一种方法可以使用Random.NextDouble()返回0..1之间的数字,然后将其缩放到0..26并使用查找表根据索引返回字母字符。 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. 更有效的方法是使用ascii表将整数转换为所需的字母数字字符。

Best regards, 最好的祝福,

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. 您可以创建两个随机数,其中第一个随机数的长度为6-10,第二个随机数的长度为2.生成两个数后,将它们组合成一个长度为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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM