Материал: Глава 16. LINQ

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

§16.3 Фильтрация выборки и проекция

Фильтрация

Для выбора элементов из некоторого набора по условию используется метод Where. Например, выберем все четные элементы, которые больше 10.

Фильтрация с помощью операторов LINQ:

Листинг 16.4

1int[] numbers = { 1, 2, 3, 4, 10, 34, 55, 66, 77, 88 };

2IEnumerable<int> evens = from i in numbers

3

where i%2==0 && i>10

4

select i;

5foreach (int i in evens)

6Console.WriteLine(i);

Здесь используется конструкция from: from i in numbers.

Тот же запрос с помощью метода расширения:

Листинг 16.5

1int[] numbers = { 1, 2, 3, 4, 10, 34, 55, 66, 77, 88

}

2IEnumerable<int> evens = numbers.Where(i => i % 2 == 0 && i > 10)

Если выражение в методе Where для определенного элемента будет равно true (в данном случае выражение i % 2 == 0 && i > 10), то данный элемент попадает в результирующую выборку.

Выборка сложных объектов

Допустим, у нас есть класс пользователя:

 

 

Листинг 16.6

 

 

 

 

1

class User

 

 

2

{

 

 

3

public

string Name { get;set; }

 

4

public

int Age { get; set; }

 

5

public

List<string> Languages { get; set; }

 

6

public

User()

 

7

{

 

 

8

Languages = new List<string>();

 

9

}

 

 

 

 

6

 

10 }

Создадим набор пользователей и выберем из них тех, которым больше

25 лет:

Листинг 16.7

1

List<User> users = new List<User>

2

{

3

new User {Name="Том", Age=23, Languages = new

List<string> {"английский", "немецкий" }},

 

4

new User {Name="Боб", Age=27, Languages = new

List<string> {"английский", "французский" }},

 

5

new User {Name="Джон", Age=29, Languages = new

List<string> {"английский", "испанский" }},

 

6

new User {Name="Элис", Age=24, Languages = new

List<string> {"испанский", "немецкий" }}

 

7

};

8

var selectedUsers = from user in users

9

where user.Age > 25

10

select user;

11

foreach (User user in selectedUsers)

12

Console.WriteLine($"{user.Name} - {user.Age}");

 

Аналогичный запрос с помощью метода расширения Where:

var selectedUsers = users.Where(u=> u.Age > 25);

Сложные фильтры

Теперь рассмотрим более сложные фильтры. Например, в классе пользователя есть список языков, которыми владеет пользователь. Что если нам надо отфильтровать пользователей по языку:

Листинг 16.8

1 var selectedUsers = from user in users

2 from lang in user.Languages

3 where user.Age < 28

4 where lang == "английский"

5 select user;

Для создания аналогичного запроса с помощью методов расширения

применяется метод SelectMany:

Листинг 16.9

1 var selectedUsers = users.SelectMany(u => u.Languages,

7

2

(u, l) => new { User = u, Lang = l })

3

.Where(u => u.Lang == "английский" && u.User.Age < 28)

4

.Select(u=>u.User);

Метод SelectMany() в качестве первого параметра принимает последовательность, которую надо проецировать, а в качестве второго параметра - функцию преобразования, которая применяется к каждому элементу. На выходе она возвращает 8 пар "пользователь - язык"

(new { User = u, Lang = l }),

к которым потом применяется фильтр с помощью Where.

Проекция

Проекция позволяет спроектировать из текущего типа выборки какой-то другой тип. Для проекции используется оператор select. Допустим, у нас есть набор объектов следующего класса, представляющего пользователя:

Листинг 16.10

1

class User

 

2

{

 

3

public string Name { get;set; }

 

4

public int Age { get; set; }

 

5

}

 

 

Но нам нужен не весь объект, а только его свойство Name:

 

Листинг 16.11

 

 

1

List<User> users = new List<User>();

 

2

users.Add(new User { Name = "Sam", Age = 43 });

 

3

users.Add(new User { Name = "Tom", Age = 33 });

 

4

var names = from u in users select u.Name;

 

5

foreach (string n in names)

 

6

Console.WriteLine(n);

 

Результат выражения LINQ будет представлять набор строк, поскольку выражение select u.Name выбирают в результирующую выборку только значения свойства Name.

8

Аналогично можно создать объекты другого типа, в том числе

анонимного:

 

Листинг 16.12

 

 

 

1

List<User> users = new List<User>();

 

2

users.Add(new User { Name = "Sam", Age = 43 });

 

3

users.Add(new User { Name = "Tom", Age = 33 });

 

4

var items = from u in users

 

5

select new

 

6

{

 

7

FirstName = u.Name,

 

8

DateOfBirth = DateTime.Now.Year -

 

u.Age

 

 

 

9

};

 

10

foreach (var n in items)

 

11

Console.WriteLine($"{n.FirstName} - {n.DateOfBirth}");

 

Здесь оператор select создает объект анонимного типа, используя текущий объект User. И теперь результат будет содержать набор объектов данного анонимного типа, в котором определены два свойства: FirstName и DateOfBirth.

В качестве альтернативы мы могли бы использовать метод расширения

Select():

Листинг 16.13

1

// выборка имен

 

2

var names = users.Select(u => u.Name);

3

// выборка объектов анонимного типа

4

var items = users.Select(u => new

5

{

 

6

FirstName =

u.Name,

7

DateOfBirth

= DateTime.Now.Year - u.Age

8

});

 

9

Выборка из нескольких источников

В LINQ можно выбирать объекты не только из одного, но и из большего

количества источников.

 

Например, возьмем классы:

 

Листинг 16.14

 

 

 

1

class Phone

 

2

{

 

3

public string Name { get; set; }

 

4

public string Company { get; set; }

 

5

}

 

6

class User

 

7

{

 

8

public string Name { get; set; }

 

9

public int Age { get; set; }

 

10

}

 

 

Создадим два разных источника данных и произведем выборку:

 

Листинг 16.15

 

 

1

List<User> users = new List<User>()

 

2

{

 

3

new User { Name = "Sam", Age = 43 },

 

4

new User { Name = "Tom", Age = 33 }

 

5

};

 

6

List<Phone> phones = new List<Phone>()

 

7

{

 

8

new Phone {Name="Lumia 630", Company="Microsoft"

 

},

 

 

 

9

new Phone {Name="iPhone 6", Company="Apple"},

 

10

};

 

11

var people = from user in users

 

12

from phone in phones

 

13

select new { Name = user.Name, Phone =

 

phone.Name };

 

14

foreach (var p in people)

 

15

Console.WriteLine($"{p.Name} - {p.Phone}");

 

 

Таким образом, при выборке из двух источников каждый элемент из

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

10

Источник: https://studfile.net/preview/16573801/