2013-07-29 21 views
7

Có một giải pháp thanh lịch để đi qua danh sách có thứ tự để thực hiện một số phép tính đối với hiện tại và đối tượng tiếp theo không? Có phải là một cách thông minh hơn với LINQ to làm như sau:Sử dụng LINQ để thực hiện một số phép tính trên hiện tại và đối tượng kế tiếp

public static List<double> GetHoursBetweenDates(List<DateTime> aDates) 
{ 
    List<double> lst = new List<double>(); 
    var olst = aDates.OrderByDescending(d => d).ToList(); 
    for (int i = 0; i < olst.Count - 1; i++) 
    { 
     lst.Add(olst[i].Subtract(olst[i+1]).TotalHours); 
    } 
    return lst; 
} 
+1

Hãy cẩn thận về việc phân biệt đối tượng 'DateTime' một cách mù quáng. '.Kind' có thể ảnh hưởng đến kết quả. Xem [câu trả lời này] (http://stackoverflow.com/a/17950820/634824) và [bài viết này] (http://codeofmatt.com/2013/04/25/the-case-against-datetime-now/). –

+0

Thanks @Matt Tôi sẽ ghi nhớ điều đó. – Seatech

Trả lời

11

Cách dễ dàng nhất để so sánh từng yếu tố liên tiếp trong một danh sách được một cái gì đó như thế này:

var sorted = aDates.OrderByDescending(d => d); 
var results = 
    sorted.Zip(sorted.Skip(1), (a, b) => a.Subtract(b).TotalHours); 

Ngoài ra, bạn có thể làm điều này:

var sorted = aDates.OrderByDescending(d => d).ToArray(); 
var results = 
    from i in Enumerable.Range(0, sorted.Length - 1) 
    select sorted[i].Subtract(sorted[i + 1]).TotalHours; 

Nhưng phương pháp thứ hai này sẽ chỉ hoạt động List<T>, T[] hoặc bất kỳ loại nào hỗ trợ chỉ mục kiểu mảng.

4

Bạn có thể sử dụng Incremental phương pháp khuyến nông từ moreLINQ thư viện:

public static List<double> GetHoursBetweenDates(List<DateTime> aDates) 
{ 
    return aDates.OrderByDescending(d => d) 
       .Incremental((p,n) => p.Subtract(n).TotalHours) 
       .ToList(); 
} 

Nó thực hiện chính xác những gì bạn cần:

/// <summary> 
/// Computes an incremental value between every adjacent element in a sequence: {N,N+1}, {N+1,N+2}, ... 
/// </summary> 
/// <remarks> 
/// The projection function is passed the previous and next element (in that order) and may use 
/// either or both in computing the result.< 
/// If the sequence has less than two items, the result is always an empty sequence. 
/// The number of items in the resulting sequence is always one less than in the source sequence. 
/// </remarks> 
7

Là một thay thế cho một giải pháp sử dụng Zip Enumerator LINQ, mà đòi hỏi bạn phải lặp lại trong danh sách của bạn hai lần, đây là toán tử LINQ tùy chỉnh lặp lại trên một chuỗi và trả về một "cặp chuyển động" của các phần tử:

static IEnumerable<Tuple<T, T>> Pairwise<T>(this IEnumerable<T> xs) 
{ 
    using (IEnumerator<T> enumerator = xs.GetEnumerator()) 
    { 
     if (!enumerator.MoveNext()) yield break; 
     T current = enumerator.Current; 
     while (enumerator.MoveNext()) 
     { 
      T previous = current; 
      current = enumerator.Current; 
      yield return Tuple.Create(previous, current); 
     } 
    } 
} 

Sau đó, bạn có thể áp dụng nó vào chuỗi DateTime của bạn như sau:

dates.Pairwise().Select(_ => _.Item2.Subtract(_.Item1).TotalHours); 
9

tùy chọn khác là sử dụng các chức năng tổng hợp, và trở về như tổng hợp các yếu tố hiện tại. Điều này có lợi ích bổ sung mà bạn chỉ lặp lại bộ sưu tập một lần:

public static List<double> GetHoursBetweenDates(List<DateTime> aDates) 
{ 
    List<double> lst = new List<double>(); 
    aDates.OrderByDescending(d => d).Aggregate((prev, curr) => { lst.Add(prev.Subtract(curr).TotalHours); return curr; }); 
    return lst; 
} 
Các vấn đề liên quan