Какой лучший способ преобразовать неуниверсальную коллекцию в общую коллекцию? - PullRequest
7 голосов
/ 17 февраля 2010

Я недавно учил себя LINQ и применял его к различным маленьким головоломкам. Однако одна из проблем, с которыми я столкнулся, заключается в том, что LINQ-to-objects работает только с общими коллекциями. Есть ли секретный прием / наилучшая практика для преобразования неуниверсальной коллекции в общую коллекцию?

Моя текущая реализация копирует неуниверсальную коллекцию в массив, затем оперирует этим, но мне было интересно, есть ли лучший способ?

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

Ответы [ 3 ]

10 голосов
/ 17 февраля 2010

Самым простым способом обычно является метод расширения Cast:

IEnumerable<Match> strongMatches = matches.Cast<Match>();

Обратите внимание, что это откладывается и потоковые данные, так что у вас нет полной «коллекции» как таковой - но это прекрасный источник данных для запросов LINQ.

Cast вызывается автоматически, если вы указали тип переменной диапазона в выражении запроса:

Итак, чтобы полностью преобразовать ваш запрос:

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 просто пропускает его.

1 голос
/ 17 февраля 2010

Вы можете использовать Cast или OfType на IEnumerable для конвертации. Cast выбросит недопустимое приведение, если элемент не может быть приведен к указанному типу, в то время как OfType пропустит любые элементы, которые не могут быть преобразованы.

0 голосов
/ 17 февраля 2010
matches.Cast<Match>();
...