Linq: в чем разница между Select и Where


123

SelectИ Whereметоды доступны в Linq. Что каждый разработчик должен знать об этих двух методах? Например: когда использовать одно над другим, какие преимущества от использования одного над другим и т. Д.


7
Я не думаю, что этот вопрос следует помечать как CW, возможно, на него есть однозначный ответ.
Брэндон

1
@Brandon, нет ничего плохого в том, чтобы отмечать что-то CW, если это объективно.
Rex M

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

6
В этом много плохого. CW бесполезен, и становится все более бесполезным, когда люди помечают вопросы как CW совершенно случайно
jalf

Ответы:


127

куда

находит совпадающие элементы и возвращает только те, которые соответствуют ( фильтрация ).

-> IEnumerable<A>внутрь, IEnumerable<A>наружу

Выбрать

возвращает что-то для всех элементов в источнике ( проекция / преобразование ). Это что-то может быть самими предметами, но чаще всего это своего рода проекция.

-> IEnumerable<A>внутрь, IEnumerable<B>наружу


16
Selectвсегда будет возвращать одинаковое количество элементов в списке (независимо от условий фильтрации, которые у вас могут быть). Whereможет возвращать меньше элементов в зависимости от условий вашего фильтра.
goku_da_master

И вот пример MSDN, selectи вот один дляwhere
yazanpro

По крайней мере, для меня, имея некоторый опыт работы с другими языками, это помогает думать об этом Where == filterиSelect == map
bgusach

52

Select и Where - два совершенно разных оператора, действующих на IEnumerable .

Первый - это то, что мы называем оператором проекции , а последний - оператор ограничения .

Один интересный способ понять поведение таких операторов - взглянуть на их «функциональный тип».

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

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

    Используя некоторые математические обозначения, он принимает в качестве входных данных (a, b, c, ...): IEnumerable <T1> и f: T1 → T2 и производит (f (a), f (b), f (c) , ...): IEnumerable <T2>

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

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

Люди с опытом функционального программирования обычно так думают. Это позволяет вам вывести (или хотя бы догадаться ...), что делает оператор, только взглянув на его тип!

В качестве упражнения попробуйте взглянуть на другие операторы, представленные LINQ в IEnumerables, и вывести их поведение, прежде чем просматривать документацию!



18

Select отображает перечислимый объект в новую структуру. Если вы выполните выбор в IEnumerable, вы получите массив с тем же количеством элементов, но другого типа в зависимости от указанного вами сопоставления. Где фильтрует IEnumerable, чтобы получить подмножество исходного IEnumerable.



7

Если вы знаете, как они реализовали методы расширения Where и select, вы можете предсказать, что он делает ... Я попытался реализовать где и выбрать методы расширения ... Вы можете взглянуть на это ...

Где реализация:

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

Моя реализация отлично работает для любой коллекции ... Но она отличается от методов расширения, реализованных Microsoft, потому что они используют деревья выражений для реализации того же.


1

В случае Select вы можете сопоставить IEnumerable новой структуры.

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

Where () работает как фильтр для IEnumerable, он вернет результат на основе предложения where.

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.