2012-08-09 3 views
14

Mi piacerebbe utilizzare la funzione LINQ TakeWhile su LINQ su Oggetti. Tuttavia, ho anche bisogno di conoscere il primo elemento che "ha rotto" la funzione, cioè il primo elemento in cui la condizione non era vera.TakeWhile, ma ottieni anche l'elemento che lo ha arrestato

C'è una sola funzione per ottenere tutti gli oggetti che non corrispondono, più il primo che fa?

Ad esempio, dato il set {1,2,3,4,5,6,7,8},

mySet.MagicTakeWhile(x => x != 5); 

=> {1,2,3,4,5}

+0

è possibile scrivere un metodo del genere facilmente, ma questo non sarà "pigro" in quanto è necessario conoscere la posizione dell'ultimo elemento al fine di ottenere il prossimo. –

+0

[Questa domanda] (https://stackoverflow.com/q/2242318/241211) non è un duplicato, ma condivide [una risposta.] (Https://stackoverflow.com/a/6817553/241211) – Michael

risposta

9

Penso che si possa utilizzare SkipWhile, e poi prendere il primo elemento.

var elementThatBrokeIt = data.SkipWhile(x => x.SomeThing).Take(1); 

UPDATE

Se si vuole un unico metodo di estensione, è possibile utilizzare il seguente:

public static IEnumerable<T> MagicTakeWhile<T>(this IEnumerable<T> data, Func<T, bool> predicate) { 
    foreach (var item in data) { 
     yield return item; 
     if (!predicate(item)) 
      break; 
    } 
} 
+1

Che richiederebbe più chiamate. Potrei semplicemente fare 'FirstOrDefault' in quel caso. –

+0

+1 per fornire codice di lavoro – Gabe

+0

@Maarten, buona risposta: è possibile salvare una riga rimuovendo l'interruzione di rendimento finale ' – allonhadaya

6

LINQ to Objects non ha un tale operatore. Ma è semplice implementare direttamente un'estensione TakeUntil. Ecco one such implementation da moreLinq.

+0

Sfortunatamente non lo includono in MoreLinq NuGet. Copia e incolla il codice. Grazie! –

+4

Il nome "TakeUntil'' non ne indica il significato. '' Prendi'' uova dalla scatola '' Fino a'' ottieni una brutta non vuol dire che prendi quella cattiva. – bradgonesurfing

+0

@bradgonesurfing TakeUntilInclusive? –

0

Solo per divertimento:

var a = new[] 
    { 
     "two", 
     "three", 
     "four", 
     "five", 
    }; 
    Func<string, bool> predicate = item => item.StartsWith("t");  
    a.TakeWhile(predicate).Concat(new[] { a.SkipWhile(predicate).FirstOrDefault() }) 
+0

Questo prende anche due chiamate di funzione. Inoltre, è possibile saltare "SkipWhile" e andare direttamente a "a.FirstOrDefault (predicato)". –