2010-02-28 22 views
8

Không phải là đồng bằng tổng hợp mà là đồng bằng của mỗi phần tử. Dưới đây là một số mã để giải thích ý tôi là:Tôi có thể lấy delta của hai IEnumerables trong LINQ không?

var deltaTotals = _deltaEnumerable.Select(a => a.Amount).ToList(); 
var oldTotals = _totalsEnumerable.Select(d => d.Amount).ToList(); 

// trigger change in _totalsEnumerable 

// ** can LINQ do the lines below 
var newTotals = totalsEnumerable.Select(d => d.Amount); 
for (var i = 0; i < 7; i++) { 
    var newAmount = oldTotals[i] - deltaTotals[i]; 
    Assert.That(newTotals.ElementAt(i), Is.EqualTo(newAmount)); 
} 

Đó là bốn dòng mã cuối cùng dường như có cách làm thanh lịch hơn trong LINQ bằng cách nào đó.

Chúc mừng,
Berryl

Trả lời

7

Điều bạn muốn là phương pháp mở rộng Enumerable.Zip.

Một cách sử dụng ví dụ sẽ là:

var delta = oldTotals.Zip(newTotals, (o, n) => n.Amount - o.Amount); 

Lưu ý rằng đây là mới vào NET 4.0. Trong .NET 3.5 bạn sẽ phải viết phần mở rộng của riêng bạn. Một cái gì đó như thế này:

public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
    this IEnumerable<TFirst> first, 
    IEnumerable<TSecond> second, 
    Func<TFirst, TSecond, TResult> resultSelector) 
{ 
    using (var firstEnumerator = first.GetEnumerator()) 
    using (var secondEnumerator = second.GetEnumerator()) 
    { 
     while ((firstEnumerator.MoveNext() && secondEnumerator.MoveNext())) 
     { 
      yield return resultSelector(firstEnumerator.Current, 
       secondEnumerator.Current); 
     } 
    } 
} 
+0

Làm mát. Zip dường như không có ý định tiết lộ tên với tôi nhưng ít nhất nó ngắn. Khi tôi lần đầu tiên nhìn thấy câu trả lời của bạn, tôi nghĩ rằng đó là một tải về! Chúc mừng – Berryl

+0

Đúng, đó không phải là tên dễ khám phá nhất trên thế giới. Tôi nghĩ Eric Lippert đã đặt ra thuật ngữ: http://blogs.msdn.com/ericlippert/archive/2009/05/07/zip-me-up.aspx. Dù bằng cách nào, đó là một phần mở rộng hữu ích. :) – Aaronaught

+2

tên đến từ các ngôn ngữ chức năng. Nó được gọi là như vậy bởi vì nó hoạt động giống như một dây kéo. Theo mặc định nó sẽ làm một cái gì đó giống như hình thức tuples nơi yếu tố đầu tiên đến từ danh sách 1 thứ 2 từ 2. – flq

5

Như Aaronaught đã trả lời, bạn nên sử dụng phương pháp Zip; tuy nhiên, nó không có sẵn trong .NET 3.5, chỉ có trong 4.0. Dưới đây là triển khai tùy chỉnh:

public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> selector) 
    { 
     if (first == null) 
      throw new ArgumentNullException("first"); 
     if (second == null) 
      throw new ArgumentNullException("second"); 
     if (selector == null) 
      throw new ArgumentNullException("selector"); 

     return first.ZipIterator(second, selector); 
    } 

    private static IEnumerable<TResult> ZipIterator<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> selector) 
    { 
     using (var enum1 = first.GetEnumerator()) 
     using (var enum2 = second.GetEnumerator()) 
     { 
      while (enum1.MoveNext() && enum2.MoveNext()) 
      { 
       yield return selector(enum1.Current, enum2.Current); 
      } 
     } 
    } 
+0

Ngọt ngào. Có nhiều phần mở rộng hơn như Zip trong 4.0 không? – Berryl

+0

Zip là phương pháp mới duy nhất trong lớp Enumerable, nhưng có thể có những người khác ở đâu đó ... –

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