2013-02-07 29 views
11

Hãy nói rằng tôi đã sau dữ liệu:nhóm LINQ bởi khối tiếp giáp

Time Status
10:00 On
11:00 Tắt
12:00 Tắt
13:00 Tắt
14 : 00 Tắt
15:00 On
16:00 On

Làm cách nào tôi có thể nhóm bằng cách sử dụng LINQ thành một cái gì đó như

[Bật, [10:00]], [Tắt, [11:00, 12:00, 13:00, 14:00]], [Bật, [15:00, 16:00]]

+1

Tôi nghĩ rằng đây là một bản sao có thể trùng lặp: http: // stackoverflow.com/questions/7469828/linq-query-to-split-an-trật-xếp-danh sách-vào-danh sách con-của-tiếp giáp-điểm-by-một-c – hcb

+0

Là câu hỏi, được cung cấp các dữ liệu sau để tôi có thể xác định xem thực thể là On/Off tại một thời điểm nhất định? –

Trả lời

13

Tạo một tiện ích mở rộng GroupAdjacent, chẳng hạn như số được liệt kê here.

Và sau đó nó đơn giản như:

var groups = myData.GroupAdjacent(data => data.OnOffStatus); 
1

Nó có thể được thực hiện như.

  1. Lặp lại quá trình thu thập.
  2. Sử dụng điều kiện TakeWhile<Predicate> là văn bản của phần tử thu thập đầu tiên Bật hoặc Tắt.
  3. Lặp lại tập hợp con từ điểm một và lặp lại bước trên và nối chuỗi.

Hy vọng nó giúp ..

1

Bạn có thể phân tích danh sách và gán một phím liền kề ví dụ như định nghĩa một lớp:

public class TimeStatus 
{ 
    public int ContiguousKey { get; set; } 
    public string Time { get; set; } 
    public string Status { get; set; } 
} 

Bạn sẽ gán giá trị cho các khóa tiếp giáp bởi Looping qua, duy trì đếm và phát hiện khi trạng thái thay đổi từ Bật thành Tắt và cứ thế sẽ cung cấp cho bạn danh sách như sau:

List<TimeStatus> timeStatuses = new List<TimeStatus> 
      { 
       new TimeStatus { ContiguousKey = 1, Status = "On", Time = "10:00"}, 
       new TimeStatus { ContiguousKey = 1, Status = "On", Time = "11:00"}, 
       new TimeStatus { ContiguousKey = 2, Status = "Off", Time = "12:00"}, 
       new TimeStatus { ContiguousKey = 2, Status = "Off", Time = "13:00"}, 
       new TimeStatus { ContiguousKey = 2, Status = "Off", Time = "14:00"}, 
       new TimeStatus { ContiguousKey = 3, Status = "On", Time = "15:00"}, 
       new TimeStatus { ContiguousKey = 3, Status = "On", Time = "16:00"} 
      }; 

Sau đó, sử dụng các truy vấn sau đây bạn có thể trích xuất các trạng và nhóm Times:

var query = timeStatuses.GroupBy(t => t.ContiguousKey) 
    .Select(g => new { Status = g.First().Status, Times = g }); 
3

Đây là một Hardcore giải pháp LINQ bằng cách sử dụng Enumerable.Zip để so sánh các yếu tố tiếp giáp và tạo ra một chìa khóa liền kề:

var adj = 0; 
var t = data.Zip(data.Skip(1).Concat(new TimeStatus[] { null }), 
     (x, y) => new { x, key = (x == null || y == null || x.Status == y.Status) ? adj : adj++ } 
    ).GroupBy(i => i.key, (k, g) => g.Select(e => e.x)); 
+0

cảm ơn chúa tôi biết điều này là gì mà không thực sự cố gắng phân tích cú pháp này –

5

Bạn cũng có thể làm điều này với một truy vấn LINQ bằng cách sử dụng một biến để theo dõi các thay đổi, như thế này.

int key = 0; 
var query = data.Select(
    (n,i) => i == 0 ? 
     new { Value = n, Key = key } : 
     new 
     { 
      Value = n, 
      Key = n.OnOffFlag == data[i - 1].OnOffFlag ? key : ++key 
     }) 
    .GroupBy(a => a.Key, a => a.Value); 

Về cơ bản, nó gán một khóa cho mỗi mục tăng khi mục hiện tại không bằng mục trước đó. Tất nhiên điều này giả định rằng dữ liệu của bạn nằm trong Danh sách hoặc Mảng, nếu không bạn sẽ phải thử một phương pháp khác

Các vấn đề liên quan