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.


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

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

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].


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


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ść


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();
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.