2017-10-11 5 views
3

J'ai un IEnumerable de valeurs sur lesquelles j'ai besoin de sauter certains éléments au début, j'utilise SkipWhile pour cela. Cependant, j'ai absolument besoin d'au moins un élément (étant donné que la séquence contient au moins un élément pour commencer). Si tous les éléments passent le prédicat (c'est-à-dire que tous les éléments sont ignorés), je ne souhaite obtenir que le dernier élément. Est-ce possible sans en quelque sorte des trucs chers commeLINQ SkipWhile - Prenez au moins un

items.SkipWhile(/* my condition */).FallbackIfEmpty(items.Last()) 

(cher comme: Il doit itérer la séquence deux fois, je voudrais éviter que)

+0

ce qui est 'points'une? C'est un 'List ', [.Last() s'exécute déjà en O (1) temps] (https://stackoverflow.com/questions/1377864/what-is-the-performance-of-the-last-extension -method-for-listt), et vous itérez seulement sur votre liste une fois –

+0

Et si vous voulez que cela fonctionne avec n'importe quel prédicat, vous ne pouvez pas contourner l'itération sur votre liste au moins une fois. –

+0

Je ne suis pas sûr si c'est moins cher mais vous pouvez utiliser IEnumerable .Reverse() et ensuite le parcourir normalement, en retournant la première correspondance. –

Répondre

5

LINQ ne propose pas une méthode intégrée pour ceci, mais vous pouvez écrire votre propre extension.

Cette mise en œuvre est levée, pour la plupart, de Microsoft reference code:

public static IEnumerable<TSource> SkipWhileOrLast<TSource>(
    this IEnumerable<TSource> source, 
    Func<TSource, bool> predicate 
) { 
    bool yielding = false; 
    TSource last = default(TSource); 
    bool lastIsAssigned = false; 
    foreach (TSource element in source) { 
     if (!yielding && !predicate(element)) { 
      yielding = true; 
     } 
     if (yielding) { 
      yield return element; 
     } 
     lastIsAssigned = true; 
     last = element; 
    } 
    if (!yielding && lastIsAssigned) { 
     yield return last; 
    } 
}