LINQ gdzie vs takewhile

99

Chcę zobaczyć różnicę między metodami takewhile i where LINQ. Otrzymałem następujące dane z MSDN, ale to nie miało dla mnie sensu

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

Filtruje sekwencję wartości na podstawie predykatu.

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

Zwraca elementy z sekwencji, o ile określony warunek jest prawdziwy.

Mile widziane wszystkie opinie.

Mohammed Thabet
źródło
1
Dobre pytanie - Intellisense w TakeWhile nadal mówi „Zwraca elementy ... o ile określony warunek jest prawdziwy”. Można to bardzo dobrze zinterpretować jako to samo, co gdzie. Sformułowanie powinno raczej wyglądać mniej więcej tak: „Zwraca elementy ... dopóki warunek nie zostanie uznany za fałszywy”.
Peter,

Odpowiedzi:

159

TakeWhile zatrzymuje się, gdy warunek jest fałszywy, Where kontynuuje i znajduje wszystkie elementy pasujące do warunku

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);

Daje

Where
1
2
3
-1
-2
TakeWhile
1
2
3
Albin Sunnanbo
źródło
30

Where może zbadać całą sekwencję w poszukiwaniu dopasowań.

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

TakeWhile przestaje szukać, gdy napotka pierwszy niedopasowanie.

Enumerable.Range(1, 10).TakeWhile(x => x % 2 == 1)
// 1
Amy B.
źródło
9

Powiedzmy, że masz tablicę, która zawiera [1, 3, 5, 7, 9, 0, 2, 4, 6, 8]. Teraz:

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

var whileTest = array.TakeWhile(i => i <= 5);powróci [1, 3, 5].

Jim Mischel
źródło
Myślę whileTest powróci tylko 1 zależy @David B i @Albin Sunnanbo odpowiedzi
Mohammed Thabet
Nie, zwróci elementy, dopóki warunek nie zostanie spełniony. W tym przypadku 1, 3 i 5 spełniają warunek (są <= 5).
Jim Mischel
8

MSDN mówi

Enumerable.TakeWhile Method

Zwraca elementy z sekwencji, o ile określony warunek jest prawdziwy, a następnie pomija pozostałe elementy.

Enumerable.Where

Filtruje sekwencję wartości na podstawie predykatu.

Różnica polega na tym, że Enumerable.TakeWhile pomija pozostałe elementy z pierwszego niedopasowania, niezależnie od tego, czy spełniają warunek, czy nie

naveen
źródło
6

Chociaż istniejące odpowiedzi są poprawne, żadna z nich nie wskazuje, dlaczego chcesz użyć TakeWhile, jeśli wyniki byłyby takie same: Wydajność. Załóżmy, że masz uporządkowaną listę z 2 miliardami pozycji i chcesz mieć te, które (prawdopodobnie 10 lub 15 pozycji) są mniejsze niż podana wartość. Klauzula Where zbada wszystkie 2 miliardy elementów, a TakeWhile zatrzyma się, gdy tylko znajdzie wartość równą lub większą niż podana wartość

jmoreno
źródło
5

Kolejność przekazanej sekwencji jest absolutnie krytyczna przy użyciu TakeWhile, która zakończy się, gdy tylko predykat powróci false, podczas gdy Wherebędzie nadal oceniać sekwencję poza pierwszą falsewartością.

Typowe użycie for TakeWhilejest podczas leniwego oceniania dużych, drogich lub nawet nieskończonych wyliczeń, gdzie możesz mieć dodatkową wiedzę na temat kolejności sekwencji.

np. Biorąc pod uwagę sekwencję:

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

A .Wherespowoduje nieskończoną pętlę próbującą oszacować część wyliczalnej:

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

Natomiast a .TakeWhile, uzbrojony w wiedzę, że wyliczenia rosną, pozwoli ocenić sekwencję częściową:

var result = InfiniteSequence()
    .TakeWhile(n => n < 100)
    .Count();
StuartLC
źródło