Ngày ngẫu nhiên trong C #


141

Tôi đang tìm kiếm một số mã C # hiện đại, ngắn gọn để tạo một ngày ngẫu nhiên giữa ngày 1 tháng 1 năm 1995 và ngày hiện tại.

Tôi đang nghĩ một số giải pháp sử dụng Enumerable.Range bằng cách nào đó có thể làm cho điều này ngắn gọn hơn.


Trả lời trong Ngày ngẫu nhiên giữa phạm vi - đầu ra không thống nhất có phương thức trợ giúp với các tham số Từ / Đến ngày
Michael Freidgeim

Câu trả lời:


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

Để có hiệu suất tốt hơn nếu điều này sẽ được gọi nhiều lần, hãy tạo các biến startgen(và có thể thậm chí range) bên ngoài hàm.


1
Ngẫu nhiên chỉ là giả ngẫu nhiên. Nếu bạn thực sự cần ngẫu nhiên, hãy thử sử dụng RNGCryptoServiceProvider từ không gian tên System.Security.Cryptography.
tvanfosson

Cảm ơn tvanfosson. Giả ngẫu nhiên là đủ cho vấn đề này.
Judah Gabriel Himango

5
Trên thực tế, Random thậm chí không đặc biệt giả ngẫu nhiên trừ khi bạn giữ cá thể đó một lúc và tiếp tục lấy các giá trị ra khỏi nó.
David Mitchell

2
Đó là lý do tại sao đây chỉ là một mẫu, chứ không phải là mã sản xuất.
Joel Coehoorn

1
Đúng, điều đó làm việc cho tôi; mã trong thế giới thực của tôi sẽ có phiên bản Ngẫu nhiên bên ngoài phương thức.
Judah Gabriel Himango

25

Đây là phản ứng nhẹ với nhận xét của Joel về việc tạo ra một phiên bản tối ưu hơn một chút. Thay vì trả lại một ngày ngẫu nhiên trực tiếp, tại sao không trả về một hàm tạo có thể được gọi liên tục để tạo một ngày ngẫu nhiên.

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

Bạn có thể giải thích làm thế nào điều này là có lợi? Thay vào đó, không thể bắt đầu, gen và phạm vi là thành viên của lớp?
Đánh dấu A. Nicolosi

Họ có thể và trong trường hợp này là họ. Dưới mui xe, điều này sẽ tạo ra một đóng cửa từ vựng, đó là một cụm có chứa bắt đầu, gen và phạm vi là thành viên. Đây chỉ là ngắn gọn hơn.
JaredPar

Chức năng tuyệt vời, tôi chỉ hy vọng rằng không ai sẽ sử dụng nó như:for (int i = 0; i < 100; i++) { array[i].DateProp = RandomDayFunc()(); }
Aidiakapi

2
Làm thế nào là chức năng này được sử dụng, ai đó có thể vui lòng giải thích? Ý tôi là làm thế nào tôi có thể gọi nó?
Burak Karakuş

2
@ BurakKarakuş: Bạn nhận được một nhà máy trước: var getRandomDate = RandomDayFunc();sau đó bạn gọi nó để có được những ngày ngẫu nhiên: Hãy var randomDate = getRandomDate();nhớ rằng bạn cần sử dụng lại getRandomDate để điều này hữu ích hơn câu trả lời của Joel.
Şafak Gür

8

Tôi đã lấy câu trả lời của @Joel Coehoorn và thực hiện các thay đổi mà anh ấy đã khuyến khích - đưa biến ra khỏi phương thức và đưa tất cả vào lớp. Cộng với thời gian là ngẫu nhiên quá. Đây là kết quả.

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

Và ví dụ cách sử dụng để viết 100 DateTimes ngẫu nhiên vào bảng điều khiển:

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

Tại sao bạn tạo Random () hai lần? Một lần trong lớp khai báo biến gen và lần khác trong c-tor?
pixel

Vâng, một lần là đủ. Tôi sửa nó rồi.
prespic

1
Nó nhanh hơn khoảng bốn lần để tạo ra chỉ một số giây ngẫu nhiên và thêm số đó vào ngày bắt đầu của bạn: range = (int)(DateTime.Today - start).TotalSeconds;return start.AddSeconds(gen.Next(range));.
Phụng vụ

5

Chà, nếu bạn sẽ trình bày tối ưu hóa thay thế, chúng ta cũng có thể đi đến một trình vòng lặp:

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

bạn có thể sử dụng nó như thế này:

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

1
Một điều cần xem xét giữa một iterator so với một hàm tạo là giải pháp iterator sẽ tạo ra một giá trị IDis Dùng. Điều này buộc người gọi phải xử lý hoặc trả giá để có một người hoàn thiện sống trong GC. Máy phát điện không cần xử lý
JaredPar

2
@JaredPar, điều đó không hoàn toàn đúng. Chỉ vì một loại thực hiện IDis Dùng không có nghĩa là nó có thể hoàn thành.
vẽ Noakes

3

Bắt đầu với một đối tượng ngày cố định (ngày 1 tháng 1 năm 1995) và thêm số ngày ngẫu nhiên với AddDays (đáng chú ý, chú ý không vượt quá ngày hiện tại).


Cảm ơn Friol. Tôi sẽ hỏi làm thế nào để giới hạn số lượng được chuyển vào ngẫu nhiên. Joel đã đăng một ví dụ với mẫu mã, vì vậy tôi sẽ đánh dấu câu trả lời của anh ấy là câu trả lời.
Judah Gabriel Himango

0

Tôi đến hơi muộn trong trò chơi, nhưng đây là một giải pháp hoạt động tốt:

    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

Phương thức nhỏ trả về một ngày ngẫu nhiên dưới dạng chuỗi, dựa trên một số tham số đầu vào đơn giản. Được xây dựng dựa trên các biến thể từ các câu trả lời trên:

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);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.