Мне интересно, как сделать то же самое, используя LINQ
Дайте кому-нибудь рыбу, и вы накормите ее на день; научи их ловить рыбу, бла-бла-бла.
Вам нужен мыслительный процесс для кода LINQ. Вот процесс, который я использую.
Первое, что я делаю, это смотрю на описание проблемы и думаю: «Где операции, которые выполняются для каждого элемента последовательности?»
для каждой строковой строки в myList я хотел получить n-е слово.
Ох, есть один.
Следующий вопрос: предположим, я хотел сделать это для отдельного элемента последовательности; как бы я это сделал? Могу ли я написать метод, который делает это?
Эта проблема, похоже, красиво разбивается на две подзадачи:
1) Получив строку, верните последовательность слов.
2) Учитывая последовательность вещей, создайте последовательность каждой n-й вещи.
Мы знаем, как сделать первый: это Split()
.
Какой второй? Еще раз у нас есть операция, в которой мы что-то делаем с каждым элементом последовательности. На этот раз мы фильтруем , поэтому вполне вероятно, что мы захотим использовать Where
.
Как уже отмечали другие, вы можете использовать Where
, который принимает индекс для этого. Давайте напишем вспомогательный метод:
public static IEnumerable<T> TakeEveryNth(
this IEnumerable<T> items,
int n,
int offset = 0) =>
items.Where((item, i) => (i - offset) % n == 0);
(Обратите внимание на что-то об этом решении: там нет ничего, что было бы специфично для последовательностей строк, поэтому я сделал его универсальным. Теперь у нас есть полезный инструмент не только для слов.)
супер. Давайте сложим последние два вместе:
public static IEnumerable<string> EveryNthWord(
this string sentence,
int n,
int offset = 0) =>
sentence.Split(" ").TakeEveryNth(n, offset);
ОК, мы хотим сделать это для каждого элемента в списке, а затем объединить результаты все вместе. Это SelectMany
. Итак, решение вашей проблемы:
public static IEnumerable<string> EveryNthWord(
this IEnumerable<string> sentences,
int n,
int offset = 0) =>
sentences.SelectMany(sentence => sentence.EveryNthWord(n, offset));
А теперь у нас есть решение вашей проблемы:
var result = sentences.EveryNthWord(2, 1).ToList();
И мы закончили.
Вот как вы решаете проблему, когда пытаетесь найти решение LINQ: разбивайте все на крошечные кусочки и пишите метод для каждого кусочка, который хорошо решает одну проблему. Затем объедините их вместе с операторами запросов.
Что, если мы захотим сделать все это в одном выражении? Гораздо проще сделать это, если оно уже разбито. Просто объедините их вместе:
var n = 2;
var offset = 1;
var result = sentences
.SelectMany(sentence => sentence
.Split(" ")
.Where((item, i) => (i - offset) % n == 0))
.ToList();
Но, откровенно говоря, код более полезен и читабелен, если вы не разбиваете его. Каждый вспомогательный метод полезен сам по себе, так что держите его!