Linq: Яка різниця між Select і Where


122

SelectІ Whereметоди доступні в Linq. Що повинен знати кожен розробник про ці два методи? Наприклад: коли використовувати один над іншим, будь-які переваги використання одного над іншим тощо.


7
Я не думаю, що це питання слід позначати як CW, воно, можливо, може мати остаточну відповідь.
Брендон

1
@Brandon немає нічого поганого в тому, щоб позначити щось CW, якщо воно об'єктивне.
Рекс М

@Rex, я згоден. Просто кажучи, що різниця між Select і Where має остаточну відповідь, а друга частина питання, ймовірно, буде ґрунтуватися на загальноприйнятій практиці. Я щойно вказував це на випадок, якщо ОП не впевнений у позначенні речей як CW. Якщо він все-таки мав намір це зробити CW, то мені добре.
Брендон

6
З цим багато не так. CW марний, і тим більше, коли люди позначають питання абсолютно навмання як CW
jalf

Відповіді:


126

Де

знаходить елементи, які відповідають, і повертає лише ті, що роблять ( фільтрація )

-> IEnumerable<A>в, IEnumerable<A>поза

Виберіть

повертає щось для всіх елементів джерела ( проекція / перетворення ). Це може бути самим предметом, але це, як правило, проекція якоїсь форми.

-> IEnumerable<A>в, IEnumerable<B>поза


15
Selectзавжди буде повертати однакову кількість елементів у списку (незалежно від умови фільтра). Whereможе повернути менше елементів залежно від стану вашого фільтра.
goku_da_master

А ось приклад з MSDN selectі тут є один дляwhere
yazanpro

Принаймні для мене, маючи деякий досвід з іншими мовами, це допомагає думати про це Where == filterіSelect == map
bgusach

52

Виберіть і Де є два абсолютно різні оператори, які діють на IEnumerable s.

Перший - це те, що ми називаємо Оператором проекції , а останній - Оператором обмеження .

Один цікавий спосіб зрозуміти поведінку таких операторів - поглянути на їх "функціональний тип".

  • Виберіть: (IEbroume <T1>, Func <T1, T2>) → IEnumerable <T2> ; він приймає як вхід як IE Число, що містить елементи типу T1, так і функцію, що перетворює елементи типу T1 в елементи типу T2. Вихід - IE численні елементи, що містять тип T2.

    З цього можна легко здогадатися, що цей оператор буде виробляти свій результат, застосовуючи функцію введення на кожному елементі вхідного IEnumerable та обгортаючи результати всередині нового IEnumerable.

    Використовуючи деякі математичні позначення, він приймає як вхідні дані (a, b, c, ...): IE Численні <T1> і f: T1 → T2 і виробляють (f (a), f (b), f (c) , ...): IE Численні <T2>

  • Де: (IE численні <T1>, Func <T1, bool>) → IEnumerable <T1> ; цей приймає IE численні елементи, що містять тип T1 і предикат на T1 (тобто функцію, яка створює бульний результат для вводу типу T1). Ви бачите, що вихід є також IEnumerable, що містить елементи типу T1.

    Цього разу можна здогадатися, що елемент вхідного IEnumerable буде присутній на виході IEnumerable залежно від результату застосування присудка до елемента. Додавши до цього семантику імені оператора, ви можете бути впевнені, що він видасть вихід IEnumerable, беручи з вхідних даних лише ті елементи, які оцінюються як істинні в застосуванні предиката.

Люди з функціональним фоном програмування зазвичай думають так. Це дозволяє вивести (або принаймні здогадуватися ...), що робить оператор, лише переглянувши його тип!

Як вправу, спробуйте подивитися на інших операторів, представлених LINQ на IEnumerables, і виведіть їх поведінку, перш ніж переглянути документацію!


47

Вони відрізняються:

Selectвсе стосується трансформації .

Whereвсе стосується фільтрації .


18

Виберіть карти, що перелічують нову структуру. Якщо ви виконаєте вибір на IEnumerable, ви отримаєте масив з однаковою кількістю елементів, але різного типу залежно від вказаного відображення. Де фільтрується IEnumerable так, що він дає вам підмножину вихідного IEnumerable.



7

Якщо ви знаєте, як вони реалізували Де і виберіть методи розширення, ви можете передбачити, що це робить ... Я спробував реалізувати, де і вибрати методи розширення ... Ви можете подивитися на це ...

Де реалізація ::

public static IEnumerable<Tsource> Where<Tsource> ( this IEnumerable<Tsource> a , Func<Tsource , bool> Method )
{

    foreach ( var data in a )
    {
        //If the lambda Expression(delegate) returns "true" Then return the Data. (use 'yield' for deferred return)
        if ( Method.Invoke ( data ) )
        {
            yield return data;
        }
    }
}

Вибрати реалізацію ::

public static IEnumerable<TResult> Select<TSource , TResult> ( this IEnumerable<TSource> a , Func<TSource , TResult> Method )
{
    foreach ( var item in a )
    {
        //Each iteration call the delegate and return the Data back.(use 'yield' for deferred return)
        yield return Method.Invoke ( item );
    }
}

Моя реалізація чудово працює для будь-якої колекції ... Але вона відрізняється від методів розширення, впроваджених Майкросою, оскільки вони використовують дерева виразів, щоб реалізувати те саме.


1

У разі Select it ви можете зіставити IEnumerable нової структури.

  A.Select(x=>new X{UID=x.uid, UNAME=x.uname}) 
  //input as [IEnumerable<A>] -------->  return output as [IEnumerable<X> ]

Там, де () працює як фільтр до IEnumerable, він поверне результат на основі пункту де.

A.Where(x=>x.uid!=0) //input as [IEnumerable<A>] -------->  return output as [IEnumerable<A> ]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.