开发者

What's the best way to convert non-generic collection to a generic collection?

I've been teaching myself LINQ recently and applying it to various little puzzles. However, one of the problems I have run into is that LINQ-to-objects only works on generic collections. Is there a secret trick/ best practice for converting a non-generic collection to a generic collection?

My current implementation copie开发者_如何学Pythons the non-generic collection to an array then operates on that, but I was wondering if there was a better way?

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


The simplest way is usually the Cast extension method:

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

Note that this is deferred and streams its data, so you don't have a full "collection" as such - but it's a perfectly fine data source for LINQ queries.

Cast is automatically called if you specify a type for the range variable in a query expression:

So to convert your query completely:

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

or

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

In fact, you don't need to call OrderByDescending and then First here - you just want the maximal value, which the Max method gets you. Even better, it lets you specify a projection from a source element type to the value you're trying to find, so you can do without the Select too:

public static int MaxSequence(string str)
{      
    MatchCollection matches = Regex.Matches(str, "H+|T+");
    return matches.Cast<Match>()
                  .Max(match => match.Value.Length);
}

If you have a collection which has some elements of the right type but some which may not be, you can use OfType instead. Cast throws an exception when it encounters an item of the "wrong" type; OfType just skips over it.


You can use Cast or OfType on an IEnumerable to convert. Cast will throw illegal cast if the element cannot be cast to the stated type while OfType will skip any elements that cannot be converted.


matches.Cast<Match>();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜