วันสุ่มใน C #


141

ฉันกำลังมองหารหัส C # ที่สั้นและทันสมัยเพื่อสร้างวันที่สุ่มระหว่างวันที่ 1 มกราคม 1995 และวันที่ปัจจุบัน

ฉันคิดว่าวิธีการแก้ปัญหาที่ใช้ Enumerable บางช่วงอาจทำให้รวบรัดมากขึ้น


คำตอบในRandomTimeTime แบบสุ่มระหว่างช่วง - เอาต์พุตแบบรวมไม่ได้มีเมธอดตัวช่วยพร้อมด้วยพารามิเตอร์ From / To date
Michael Freidgeim

คำตอบ:


241
private Random gen = new Random();
DateTime RandomDay()
{
    DateTime start = new DateTime(1995, 1, 1);
    int range = (DateTime.Today - start).Days;           
    return start.AddDays(gen.Next(range));
}

เพื่อประสิทธิภาพที่ดีขึ้นหากเรียกสิ่งนี้ซ้ำ ๆ ให้สร้างตัวแปรstartและgen(และอาจรวมถึงrange) นอกฟังก์ชัน


1
สุ่มสุ่มหลอกเท่านั้น หากคุณต้องการสุ่มอย่างแท้จริงลองใช้ RNGCryptoServiceProvider จาก System.Security.Cryptography namespace
tvanfosson

ขอบคุณ tvanfosson การสุ่มหลอกก็เพียงพอแล้วสำหรับปัญหานี้
Judah Gabriel Himango

5
ที่จริงแล้วการสุ่มไม่ได้เป็นการสุ่มหลอกโดยเฉพาะอย่างยิ่งถ้าคุณไม่เก็บอินสแตนซ์ไว้ซักพักหนึ่งและรับค่าออกมา
David Mitchell

2
นี่คือเหตุผลว่าทำไมนี่เป็นเพียงตัวอย่างแทนที่จะใช้รหัสการผลิต
Joel Coehoorn

1
ใช่นั่นเหมาะกับฉัน รหัสโลกแห่งความจริงของฉันจะมีอินสแตนซ์แบบสุ่มนอกตัววิธี
Judah Gabriel Himango

25

นี่คือการตอบสนองเล็กน้อยต่อความคิดเห็นของโจเอลเกี่ยวกับการสร้างเวอร์ชั่นที่ได้รับการปรับปรุงให้ดีขึ้นเล็กน้อย แทนที่จะส่งคืนวันที่แบบสุ่มโดยตรงทำไมไม่ส่งคืนฟังก์ชันตัวสร้างซึ่งสามารถเรียกซ้ำ ๆ เพื่อสร้างวันที่แบบสุ่ม

Func<DateTime> RandomDayFunc()
{
    DateTime start = new DateTime(1995, 1, 1); 
    Random gen = new Random(); 
    int range = ((TimeSpan)(DateTime.Today - start)).Days; 
    return () => start.AddDays(gen.Next(range));
}

คุณช่วยอธิบายได้ว่าสิ่งนี้มีประโยชน์อย่างไร ไม่สามารถเริ่ม Gen และ Range เป็นสมาชิกคลาสแทนได้หรือไม่
Mark A. Nicolosi

พวกเขาสามารถและในกรณีนี้พวกเขา ภายใต้ประทุนนี้จะสร้างการปิดคำศัพท์ซึ่งเป็น clrass ที่มีการเริ่มต้น gen และช่วงในฐานะสมาชิก นี่เป็นเพียงข้อสรุปที่กระชับกว่า
JaredPar

ฟังก์ชั่นที่ดีฉันแค่หวังว่าจะไม่มีใครใช้มันเป็น:for (int i = 0; i < 100; i++) { array[i].DateProp = RandomDayFunc()(); }
Aidiakapi

2
มีการใช้ฟังก์ชั่นนี้อย่างไรบางคนช่วยอธิบายได้ไหม? ฉันหมายถึงฉันจะเรียกมันได้อย่างไร
Burak Karakuş

2
@ BurakKarakuş: คุณได้โรงงานมาก่อน: var getRandomDate = RandomDayFunc();จากนั้นคุณเรียกมันว่าเพื่อรับวันที่สุ่ม: var randomDate = getRandomDate();ใจที่คุณต้องนำ getRandomDate กลับมาใช้ใหม่เพื่อให้สิ่งนี้มีประโยชน์มากกว่าคำตอบของ Joel
ŞafakGür

8

ฉันได้รับ @Joel Coehoorn ตอบและทำการเปลี่ยนแปลงที่เขาแนะนำ - นำตัวแปรออกจากวิธีการและวางไว้ในชั้นเรียน บวกตอนนี้เวลาก็ถูกสุ่มด้วย นี่คือผลลัพธ์

class RandomDateTime
{
    DateTime start;
    Random gen;
    int range;

    public RandomDateTime()
    {
        start = new DateTime(1995, 1, 1);
        gen = new Random();
        range = (DateTime.Today - start).Days;
    }

    public DateTime Next()
    {
        return start.AddDays(gen.Next(range)).AddHours(gen.Next(0,24)).AddMinutes(gen.Next(0,60)).AddSeconds(gen.Next(0,60));
    }
}

และตัวอย่างวิธีใช้เพื่อเขียน DateTimes แบบสุ่ม 100 รายการไปยังคอนโซล:

RandomDateTime date = new RandomDateTime();
for (int i = 0; i < 100; i++)
{
    Console.WriteLine(date.Next());
}

ทำไมคุณถึงสร้าง Random () สองครั้ง? หนึ่งครั้งในการประกาศ gen class และเวลาอื่นใน c-tor
พิกเซล

ใช่ครั้งเดียวก็พอ ฉันซ่อมมัน.
2560

1
มันเป็นเรื่องของสี่ครั้งได้เร็วขึ้นในการสร้างเพียงจำนวนสุ่มเดียวของวินาทีและเพิ่มว่าวันเริ่มต้นของคุณ: และrange = (int)(DateTime.Today - start).TotalSeconds; return start.AddSeconds(gen.Next(range));
สวดมนต์

5

ถ้าคุณจะนำเสนอการเพิ่มประสิทธิภาพทางเลือกเราสามารถไปทำซ้ำได้:

 static IEnumerable<DateTime> RandomDay()
 {
    DateTime start = new DateTime(1995, 1, 1);
    Random gen = new Random();
    int range = ((TimeSpan)(DateTime.Today - start)).Days;
    while (true)
        yield return  start.AddDays(gen.Next(range));        
}

คุณสามารถใช้มันแบบนี้:

int i=0;
foreach(DateTime dt in RandomDay())
{
    Console.WriteLine(dt);
    if (++i == 10)
        break;
}

1
สิ่งหนึ่งที่ต้องพิจารณาระหว่างตัววนซ้ำกับฟังก์ชันตัวสร้างคือโซลูชันตัววนซ้ำจะสร้างค่า IDisposable วิธีนี้บังคับให้ผู้โทรต้องทิ้งหรือจ่ายราคาของการมี finalizer อยู่ใน GC เครื่องกำเนิดไฟฟ้าไม่จำเป็นต้องกำจัด
JaredPar

2
@ JaredPar ไม่ถูกต้องนัก เพียงเพราะชนิดของการดำเนินการ IDisposable ไม่ได้หมายความว่ามันจะจบลงได้
Drew Noakes

3

เริ่มต้นด้วยวัตถุวันที่คงที่ (1 มกราคม 1995) และเพิ่มจำนวนวันแบบสุ่มด้วย AddDays (ตามลำดับโปรดทราบว่าไม่เกินวันที่ปัจจุบัน)


ขอบคุณ Friol ฉันจะถามว่าจะ จำกัด จำนวนที่ส่งเป็นแบบสุ่มได้อย่างไร Joel ได้โพสต์ตัวอย่างพร้อมโค้ดตัวอย่างดังนั้นฉันจะทำเครื่องหมายคำตอบของเขาว่าเป็นคำตอบ
Judah Gabriel Himango

0

ฉันมาสายไปนิดหน่อย แต่นี่เป็นวิธีแก้ปัญหาที่ใช้ได้ดี:

    void Main()
    {
        var dateResult = GetRandomDates(new DateTime(1995, 1, 1), DateTime.UtcNow, 100);
        foreach (var r in dateResult)
            Console.WriteLine(r);
    }

    public static IList<DateTime> GetRandomDates(DateTime startDate, DateTime maxDate, int range)
    {
        var randomResult = GetRandomNumbers(range).ToArray();

        var calculationValue = maxDate.Subtract(startDate).TotalMinutes / int.MaxValue;
        var dateResults = randomResult.Select(s => startDate.AddMinutes(s * calculationValue)).ToList();
        return dateResults;
    }

    public static IEnumerable<int> GetRandomNumbers(int size)
    {
        var data = new byte[4];
        using (var rng = new System.Security.Cryptography.RNGCryptoServiceProvider(data))
        {
            for (int i = 0; i < size; i++)
            {
                rng.GetBytes(data);

                var value = BitConverter.ToInt32(data, 0);
                yield return value < 0 ? value * -1 : value;
            }
        }
    }

0

เมธอดขนาดเล็กที่ส่งคืนวันที่สุ่มเป็นสตริงโดยยึดตามพารามิเตอร์อินพุตแบบง่าย สร้างขึ้นตามรูปแบบต่าง ๆ จากคำตอบข้างต้น:

public string RandomDate(int startYear = 1960, string outputDateFormat = "yyyy-MM-dd")
{
   DateTime start = new DateTime(startYear, 1, 1);
   Random gen = new Random(Guid.NewGuid().GetHashCode());
   int range = (DateTime.Today - start).Days;
   return start.AddDays(gen.Next(range)).ToString(outputDateFormat);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.