生成随机的16位字符串

时间:2018-01-26 04:00:19

标签: c#

创建随机16位字符串的更好方法是什么?我已经使用过这段代码了,您能建议一种更有效或更优雅的方式吗?

static string Random16DigitString() {
    var rand = new Random();
    return $"{rand.Next(100000000).ToString().PadLeft(8, '0')}{rand.Next(100000000).ToString().PadLeft(8, '0')}";
}

PS:我这样做的原因是创建一个0.0000000000000000形式的字符串,所以我会按照以下方式使用它:

var myString = "0." + Random16DigitString();

2 个答案:

答案 0 :(得分:1)

你的解决方案依赖于字符串操作,这会降低它的速度。

尝试:

private static Random r = new Random();

static string Random16DigitString() {
    var v = new char[16];
    for (var j = 0; j < 16; j++) v[j] = (char)(r.NextDouble()*10 + 48);
    return new string(v);
}

这将更快,因为它不依赖于串联操作,如串联或插值。它只是将随机字符戳入char数组,然后将该数组转换为字符串。在我的机器上执行您的解决方案1亿次大约需要47秒,而我的代码大约需要27秒才能产生相同的结果。

r.Next(10) + 48可以在上面的代码中工作,但它实际上有点慢。 r.Next(48,57)甚至更慢。

您的代码也可以更简单。 $"{rand.Next(100000000):D8}{rand.Next(100000000):D8}"会做同样的事情。这几乎是执行的时间。

答案 1 :(得分:-1)

以下是我最终使用的代码:

    static readonly Random rnd = new Random();
    static string Q() {
        // https://stackoverflow.com/questions/767999/random-number-generator-only-generating-one-random-number/768001#768001
        // It was decided to use a lock instead of [ThreadStatic] because this api object is designed to be used by many threads simultaneously.
        lock (rnd) {
            // Get a string representing a positive number greater than 0 and less than 1 with exactly 16 decimal places.
            // Original implementation
            //return $"0.{rnd.Next(100000000).ToString().PadLeft(8, '0')}{rnd.Next(100000000).ToString().PadLeft(8, '0')}";
            // This works but is slow
            //return rnd.NextDouble().ToString("F16");
            // Found a better faster way: https://stackoverflow.com/questions/48455624/generate-random-16-digit-string/48457354#48457354
            var chars = new char[18];
            chars[0] = '0';
            chars[1] = '.';
            for (var i = 2; i < 18; i++)
                chars[i] = (char)(rnd.NextDouble() * 10 + 48);
            return new string(chars);
        }
    }

以下是我使用的测试(感谢Jim Berg的回答)

using System;
using System.Diagnostics;
using System.Text;

namespace NetCoreApp1 {
    class Program {
        static void Main(string[] args) {

            var sync = new object();
            var rnd = new Random();

            Time("method1", () => {
                var value = $"{rnd.Next(100000000).ToString().PadLeft(8, '0')}{rnd.Next(100000000).ToString().PadLeft(8, '0')}";
            });

            Time("method2", () => {
                var value = $"{rnd.Next(100000000):D8}{rnd.Next(100000000):D8}";
            });

            Time("next double", () => {
                var value = rnd.NextDouble().ToString("F16"); // turns out surprisingly slow, even slower than the first two
            });

            Time("method3", () => {
                var v = new char[16];
                for (var j = 0; j < 16; j++)
                    v[j] = (char)(rnd.NextDouble() * 10 + 48); // fastest
                var value = new string(v);
            });

            Time("method3 with lock", () => {
                lock (sync) {
                    var v = new char[16];
                    for (var j = 0; j < 16; j++)
                        v[j] = (char)(rnd.NextDouble() * 10 + 48); // a tiny bit slower with the lock
                    var value = new string(v);
                }
            });

            Time("method4", () => {
                var sb = new StringBuilder(16);
                for (var j = 0; j < 16; j++)
                    sb.Append((char)(rnd.NextDouble() * 10 + 48)); // slower than method 3
                var value = sb.ToString();
            });

            Console.WriteLine("Press Enter to exit.");
            Console.ReadLine();
        }

        static void Time(string testName, Action action) {
            var sw = Stopwatch.StartNew();
            for (var i = 0; i < 10000000; i++)
                action();
            sw.Stop();
            Console.WriteLine($"{testName}: {sw.ElapsedMilliseconds}ms");
        }

    }
}