Я преподавал мне LINQ недавно и применял его к различным небольшим загадкам. Однако одна из проблем, с которыми я столкнулся, - то, что LINQ к объектам только работает над универсальными наборами. Существует ли секретный прием / лучшая практика для преобразования неуниверсального набора к универсальному набору?
Моя текущая реализация копирует неуниверсальный набор в массив, затем воздействует на это, но я задавался вопросом, был ли лучший путь?
public static int maxSequence(string str)
{
MatchCollection matches = Regex.Matches(str, "H+|T+");
Match[] matchArr = new Match[matches.Count];
matches.CopyTo(matchArr, 0);
return matchArr
.Select(match => match.Value.Length)
.OrderByDescending(len => len)
.First();
}
Самым простым способом обычно является метод расширения Cast
-
IEnumerable<Match> strongMatches = matches.Cast<Match>();
Обратите внимание, что он является отложенным и передает свои данные потоком, поэтому у вас нет полноценной "коллекции" как таковой - но это совершенно прекрасный источник данных для LINQ-запросов.
Cast
вызывается автоматически, если вы указываете тип переменной range в выражении запроса:
Так что для полного преобразования вашего запроса:
public static int MaxSequence(string str)
{
return (from Match match in Regex.Matches(str, "H+|T+")
select match.Value.Length into matchLength
orderby matchLength descending
select matchLength).First();
}
или
public static int MaxSequence(string str)
{
MatchCollection matches = Regex.Matches(str, "H+|T+");
return matches.Cast<Match>()
.Select(match => match.Value.Length)
.OrderByDescending(len => len)
.First();
}
На самом деле, вам не нужно вызывать OrderByDescending
, а затем First
здесь - вам просто нужно максимальное значение, которое вам дает метод Max
. Еще лучше то, что он позволяет указать проекцию от типа исходного элемента к значению, которое вы пытаетесь найти, так что вы можете обойтись и без Select
:
public static int MaxSequence(string str)
{
MatchCollection matches = Regex.Matches(str, "H+|T+");
return matches.Cast<Match>()
.Max(match => match.Value.Length);
}
Если у вас есть коллекция, в которой есть некоторые элементы правильного типа, но есть и те, которые могут быть не правильными, вы можете использовать OfType
вместо этого. Cast
выбрасывает исключение, когда встречает элемент "неправильного" типа; OfType
просто пропускает его.
Вы можете использовать Cast
или OfType
на IEnumerable
для преобразования. Cast
бросит ошибку приведения, если элемент не может быть приведен к указанному типу, а OfType
пропустит все элементы, которые не могут быть преобразованы.