2010-10-19 2 views
17

Existe-t-il une méthode Linq pour savoir quel est l'élément suivant dans la séquence pendant l'itération? Comme exemple concret, que j'ai une liste des ints, et je veux calculer la différence entre chaque élément et son successeur, ainsi, par exemple, je voudrais pouvoir écrireLinq façon d'obtenir la différence par morceaux entre l'élément et l'élément suivant dans la liste

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

où le résultat que je veux est une liste {2,5, -6,8}.

De toute évidence, cela est trivial dans une boucle for, mais quelqu'un peut-il penser à un linéaire à Linq pour faire ce travail?

+0

cette question pourrait vous aider http://stackoverflow.com/questions/2680228/linq-next-item-in-list –

Répondre

32

Si vous utilisez .NET 4 alors vous pourriez Zip et Skip:

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

Si vous utilisez une ancienne version du cadre, et/ou que vous vouliez un peu façon plus efficace de faire cela, vous pouvez ensuite créer une méthode simple d'extension:

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; c'est exactement ce que j'aurais répondu si j'avais su qu'une fonction Zip() existait. – KeithS

+0

@Keith Ou vous pouvez l'utiliser de MoreLinq pour .NET 3.5. –

+0

Le seul inconvénient mineur de cette solution est que myList sera énuméré deux fois. Peut être facilement fixé avec la méthode Memoize de Reactive Extensions for .NET (Rx). –

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

En supposant que la liste comporte au moins 2 éléments.

Questions connexes