LINQ where vs takewhile

99

Я хочу различить методы TakeWhile& WhereLINQ. Я получил следующие данные из MSDN. Но для меня это не имело смысла.

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

Фильтрует последовательность значений на основе предиката.

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

Возвращает элементы из последовательности, пока выполняется указанное условие.

Все мнения приветствуются.

Мохаммед Табет
источник
1
Хороший вопрос - Intellisense на TakeWhile по-прежнему говорит: «Возвращает элементы ... пока выполняется указанное условие». Это вполне можно интерпретировать как то же самое, что и Where. Формулировка должна быть чем-то вроде «Возвращает элементы ... до тех пор, пока условие не будет оценено как ложное».
Питер

Ответы:

159

TakeWhileостанавливается, когда условие ложно, Whereпродолжается и находит все элементы, соответствующие условию

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

Дает

Where
1
2
3
-1
-2
TakeWhile
1
2
3
Альбин Суннанбо
источник
31

Where можно просмотреть всю последовательность в поисках совпадений.

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

TakeWhile перестает искать, когда встречает первое несовпадение.

Enumerable.Range(1, 10).TakeWhile(x => x % 2 == 1)
// 1
Эми Б
источник
короткий и милый, идеальный ответ
Neuron
9

Скажем, у вас есть массив, содержащий [1, 3, 5, 7, 9, 0, 2, 4, 6, 8]. Сейчас:

var whereTest = array.Where(i => i <= 5);вернется [1, 3, 5, 0, 2, 4].

var whileTest = array.TakeWhile(i => i <= 5);вернется [1, 3, 5].

Джим Мишель
источник
Я думаю, whileTest вернет только 1, зависит от ответов @David B и @Albin Sunnanbo
Мохаммед Табет
Нет, он будет возвращать товары до тех пор, пока условие не будет выполнено. В этом случае условию удовлетворяют 1, 3 и 5 (они <= 5).
Джим Мишель
9

MSDN говорит

Enumerable.TakeWhile Method

Возвращает элементы из последовательности, если заданное условие истинно, а затем пропускает остальные элементы.

Enumerable.Where

Фильтрует последовательность значений на основе предиката.

Разница в том, что Enumerable.TakeWhile остальные элементы из первого несоответствия пропускаются независимо от того, соответствуют они условию или нет.

навин
источник
7

Порядок переданной последовательности абсолютно критичен с TakeWhile, который прекратится, как только предикат вернется false, тогда какWhere будет продолжать оценивать последовательность после первого falseзначения.

Обычное использование для TakeWhile во время ленивого вычисления больших, дорогих или даже бесконечных перечислимых элементов, когда у вас могут быть дополнительные сведения об упорядочении последовательности.

например, учитывая последовательность:

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

A .Whereприведет к бесконечному циклу, пытающемуся оценить часть перечислимого:

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

В то время как a .TakeWhileи вооруженный знанием того, что перечислимые восходящие, позволит оценить частичную последовательность:

var result = InfiniteSequence()
    .TakeWhile(n => n < 100)
    .Count();
StuartLC
источник
1
На самом деле. Это также действительно полезно для анализа последовательности токенов.
Алуан Хаддад,
7

Хотя существующие ответы верны, ни один из них не указывает, почему вы хотели бы использовать TakeWhile, если результаты будут такими же: производительность. Предположим, у вас есть упорядоченный список с 2 миллиардами элементов в нем, и вам нужны те, которые (вероятно, на 10 или 15 элементов) меньше заданного значения. Предложение Where проверит все 2 миллиарда элементов, в то время как TakeWhile остановится, как только найдет значение, равное или превышающее предоставленное вами значение.

Jmoreno
источник