2010-10-19 7 views
17

Gibt es eine Linq Weise zu wissen, was das nächste Element in der Sequenz ist während der Iteration? Als ein konkretes Beispiel, sagen, dass ich eine Liste von Ints haben, und ich möchte den Unterschied zwischen jedem Element und seinem Nachfolger, so zum Beispiel berechnen, würde ich in der Lage sein magLinq Weg stückweise Unterschied zwischen Element und nächstes Element in der Liste zu bekommen

var myList = new List<int>() { 1,3,8,2,10 }; 
var differences = myList.Select(ml => ml.Next() - ml) // pseudo-code, obviously 

zu schreiben, wo das Ergebnis möchte ich ist eine Liste {2,5, -6,8}.

Offensichtlich ist dies in einer For-Schleife trivial, aber kann jemand an einen ordentlichen Einzeiler in Linq denken, um diesen Job zu machen?

+0

diese Frage, die Ihnen http://stackoverflow.com/questions/2680228/linq-next-item-in-list helfen kann –

Antwort

32

Wenn Sie 4 verwenden sind .NET dann könnte man Zip und Skip:

var differences = myList.Zip(myList.Skip(1), (x, y) => y - x); 

Wenn Sie eine ältere Version des Frameworks verwenden, und/oder Sie wollten eine leicht effizienten dies zu tun, dann könnten Sie eine einfache Erweiterung Methode erstellen:

var differences = myList.Pairwise((x, y) => y - x); 

// ... 

public static class EnumerableExtensions 
{ 
    public static IEnumerable<T> Pairwise<T>(
     this IEnumerable<T> source, Func<T, T, T> selector) 
    { 
     if (source == null) throw new ArgumentNullException("source"); 
     if (selector == null) throw new ArgumentNullException("selector"); 

     using (var e = source.GetEnumerator()) 
     { 
      if (!e.MoveNext()) throw new InvalidOperationException("Sequence cannot be empty."); 

      T prev = e.Current; 

      if (!e.MoveNext()) throw new InvalidOperationException("Sequence must contain at least two elements."); 

      do 
      { 
       yield return selector(prev, e.Current); 
       prev = e.Current; 
      } while (e.MoveNext()); 
     } 
    } 
} 
+0

Love it; Genau das hätte ich geantwortet, wenn ich gewusst hätte, dass eine Zip() -Funktion existiert. – KeithS

+0

@Keith Oder Sie könnten es von MoreLinq für .NET 3.5 verwenden. –

+0

Der einzige kleine Nachteil dieser Lösung ist, dass myList zweimal aufgezählt wird. Kann jedoch leicht mit der Memoize-Methode von Reactive Extensions for .NET (Rx) behoben werden. –

5
var differences = myList 
    .Take(myList.Count - 1) 
    .Select((v, i) => myList[i + 1] - v); 

Angenommen, die Liste hat mindestens 2 Einträge.

Verwandte Themen