2011-12-19 42 views
15

Tôi đang viết một nhà xuất khẩu Excel cho một ứng dụng riêng biệt mà tôi đang tạo và tôi có câu hỏi về việc nhóm LINQ trong C#.Cách nhóm ngày theo tuần?

Về cơ bản, lớp xuất bản Excel mới này được cung cấp hai ngày. Lớp này sẽ truy lục tất cả các lô hàng giữa phạm vi ngày này.

Là một phần của nhà xuất khẩu này, tôi cần có thể nhóm ngày thành các tuần và nhận được các giá trị cho tuần đó. Vì vậy, ví dụ, nếu tôi được cung cấp 07/12/2011 và 22/12/2011 (định dạng dd/MM/yyyy), tôi cần phải nhóm tất cả các lô hàng giữa chúng vào khoảng tuần (mỗi tuần bắt đầu từ Chủ Nhật). Kết quả lý tưởng sử dụng các ngày ở trên sẽ là

Week 1: (consignments between 04/12/2011 and 10/12/2011) 
Week 2: (consignments between 11/12/2011 and 17/12/2011) 
Week 3: (consignments between 18/11/2011 and 24/12/2011) 

Bất kỳ ý tưởng nào?

Trả lời

28

Câu hỏi cơ bản ở đây là làm thế nào để chiếu một cá thể DateTime vào một giá trị tuần trong năm. Điều này có thể được thực hiện bằng cách gọi số Calendar.GetWeekOfYear. Vì vậy, hãy xác định phép chiếu:

Func<DateTime, int> weekProjector = 
    d => CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(
     d, 
     CalendarWeekRule.FirstFourDayWeek, 
     DayOfWeek.Sunday); 

Bạn có thể định cấu hình chính xác cách xác định "số tuần" bằng cách tinh chỉnh thông số trong cuộc gọi phương thức. Bạn cũng có thể quyết định xác định phép chiếu như ví dụ: một phương pháp mở rộng nếu bạn thích; điều này không thay đổi bản chất của mã. Trong mọi trường hợp, bạn sau đó sẵn sàng để nhóm theo tuần:

var consignmentsByWeek = from con in consignments 
         group con by weekProjector(con.Date); 

Nếu bạn cũng muốn hạn chế sản lượng để lô hàng giữa hai ngày cụ thể, chỉ cần thêm một khoản thích hợp where; logic nhóm không thay đổi.

21

Do dự mặc dù tôi không đồng ý với tư cách là người trả lời tôi tin rằng câu trả lời được chấp nhận ở đây là sai, và điều này về cơ bản không phải là câu hỏi dự báo giá trị một tuần trong năm.

GetWeekOfYear() và khái niệm nói chung, là về chỉ định giá trị chỉ mục cho các tuần trong vòng một năm theo một số tiêu chuẩn đã thỏa thuận. Nó không thích hợp để đặt ngày vào các nhóm bảy ngày liền kề như tôi tin rằng người hỏi yêu cầu.

Không chỉ sử dụng GetWeekOfYear() như kết quả được đề xuất trong các nhóm ít hơn bảy ngày vào cuối nhiều năm, nhưng vẫn còn tồi tệ hơn, vì các tiêu chuẩn khác nhau được hỗ trợ bởi GetWeekOfYear() sẽ thường phân bổ ngày đầu tiên của năm tới tuần cuối cùng của năm trước, và kết quả GetWeekOfYear() chỉ chứa chỉ số tuần nguyên không có tham chiếu đến năm kết hợp, nhóm theo new { Year = date.Year, weekProjector(date) } hoặc date.Year + "-" + weekProjector(date) trong năm của người hỏi sẽ thấy ngày 1 tháng 1 năm 2011 được nhóm với Ngày Giáng sinh qua đến Đêm Giao thừa mười hai tháng sau cùng năm đó.

Vì vậy, tôi cho rằng câu hỏi ban đầu cơ bản là một trong những dự không đến một tuần của giá trị trong năm nhưng đến một tuần của tất cả các giá trị thời gian, "Tuần bắt đầu y/m/d" bạn có thể nói, nên nhóm chỉ cần được thực hiện chậm nhất vào ngày đầu tiên của tuần, tức là (giả sử bạn đang hạnh phúc để mặc định đến chủ nhật) chỉ đơn giản là:

group by date.AddDays(-(int)date.DayOfWeek) 
+0

tôi đến câu hỏi này, bởi vì tôi đã có mã mà nhìn rất giống câu trả lời được chấp nhận. Tôi không thích nó vì cùng lý do bạn nói. Mã này đơn giản hơn và có công việc phân đoạn ngày tốt hơn. Cảm ơn! Ngoài ra, bạn có thể phân đoạn bằng cách sử dụng một ngày khác trong tuần (như Thứ Hai) bằng cách chỉ thêm ngày đó vào kết quả này. – user1304444

+0

Tôi đã sửa đổi đề xuất trong câu trả lời (câu trả lời tuyệt vời btw) để "snap" datetime đến khoảng thời gian gần nhất. 'group by date.AddDays (((int) date.DayOfWeek) <4? (- (int) date.DayOfWeek): (- (int) date.DayOfWeek + 7))' – g2server

1

Ngoài Jon's câu trả lời bạn có thể lấy ngày đầu tiên ngày trong tuần rồi nhóm theo ngày đó.

Để nhận ngày của ngày đầu tiên trong tuần. bạn có thể sử dụng mã này:

public static class DateTimeExtensions 
{ 
    public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek) 
    { 
     int diff = dt.DayOfWeek - startOfWeek; 
     if (diff < 0) 
     { 
      diff += 7; 
     } 
     return dt.AddDays(-1 * diff).Date; 
    } 
} 

sau đó bạn có thể nhóm theo ngày đầu tiên của tuần như thế này:

var consignmentsByWeek = from con in consignments 
         group con by con.Datedate.StartOfWeek(DayOfWeek.Monday); 
Các vấn đề liên quan