LINQ donde vs take while

99

Quiero obtener una diferencia entre los métodos take while y where LINQ. Obtuve los siguientes datos de MSDN. Pero no tenía sentido para mí

Where<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) 

Filtra una secuencia de valores basada en un predicado.

TakeWhile<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>)

Devuelve elementos de una secuencia siempre que una condición especificada sea verdadera.

Todas las opiniones son bienvenidas.

Mohammed Thabet
fuente
1
Buena pregunta: el Intellisense de TakeWhile todavía dice "Devuelve elementos ... siempre que una condición especificada sea verdadera". Esto podría muy bien interpretarse como lo mismo que un Dónde. La redacción debería ser algo como "Devuelve elementos ... hasta que la condición se evalúe como falsa".
Peter

Respuestas:

159

TakeWhile se detiene cuando la condición es falsa, Where continúa y encuentra todos los elementos que coinciden con la condición

var intList = new int[] { 1, 2, 3, 4, 5, -1, -2 };
Console.WriteLine("Where");
foreach (var i in intList.Where(x => x <= 3))
    Console.WriteLine(i);
Console.WriteLine("TakeWhile");
foreach (var i in intList.TakeWhile(x => x <= 3))
    Console.WriteLine(i);

Da

Where
1
2
3
-1
-2
TakeWhile
1
2
3
Albin Sunnanbo
fuente
30

Where Puede examinar toda la secuencia en busca de coincidencias.

Enumerable.Range(1, 10).Where(x => x % 2 == 1)
// 1, 3, 5, 7, 9

TakeWhile deja de mirar cuando encuentra la primera no coincidencia.

Enumerable.Range(1, 10).TakeWhile(x => x % 2 == 1)
// 1
Amy B
fuente
9

Digamos que tiene una matriz que contiene [1, 3, 5, 7, 9, 0, 2, 4, 6, 8]. Ahora:

var whereTest = array.Where(i => i <= 5);volverá [1, 3, 5, 0, 2, 4].

var whileTest = array.TakeWhile(i => i <= 5);volverá [1, 3, 5].

Jim Mischel
fuente
Creo que whileTest devolverá solo 1 depende de las respuestas de @David B y @Albin Sunnanbo
Mohammed Thabet
No, devolverá los artículos hasta que no se cumpla la condición. En este caso, 1, 3 y 5 cumplen la condición (son <= 5).
Jim Mischel
8

MSDN dice

Enumerable.TakeWhile Method

Devuelve elementos de una secuencia siempre que una condición especificada sea verdadera y luego omite los elementos restantes.

Enumerable.Where

Filtra una secuencia de valores basada en un predicado.

La diferencia es que Enumerable.TakeWhile omite los elementos restantes de la primera no coincidencia, ya sea que coincidan con la condición o no

naveen
fuente
6

Si bien las respuestas existentes son correctas, ninguna de ellas indica por qué querría usar TakeWhile si los resultados fueran los mismos: Rendimiento. Suponga que tiene una lista ordenada con 2 mil millones de elementos y desea los que (probablemente 10 o 15 elementos) sean menores que un valor determinado. La cláusula Where examinará los 2 mil millones de elementos, mientras que TakeWhile se detendrá tan pronto como encuentre un valor igual o mayor que el valor proporcionado

jmoreno
fuente
5

El orden de la secuencia pasada es absolutamente crítico con TakeWhile, que terminará tan pronto como regrese un predicado false, mientras Whereque continuará evaluando la secuencia más allá del primer falsevalor.

Un uso común de TakeWhilees durante la evaluación perezosa de enumerables grandes, costosos o incluso infinitos, donde puede tener conocimiento adicional sobre el orden de la secuencia.

por ejemplo, dada la secuencia:

IEnumerable<BigInteger> InfiniteSequence()
{
    BigInteger sequence = 0;
    while (true)
    {
        yield return sequence++;
    }
}

A .Whereresultará en un bucle infinito que intenta evaluar parte del enumerable:

var result = InfiniteSequence()
    .Where(n => n < 100)
    .Count();

Mientras que a .TakeWhile, y armado con el conocimiento de que los enumerables es ascendente, permitirá evaluar la secuencia parcial:

var result = InfiniteSequence()
    .TakeWhile(n => n < 100)
    .Count();
StuartLC
fuente