2010-02-17 29 views
7

Me he estado enseñando LINQ recientemente y aplicándolo a varios pequeños rompecabezas. Sin embargo, uno de los problemas con los que me he encontrado es que LINQ-to-objects solo funciona en colecciones genéricas. ¿Existe un truco secreto/mejor práctica para convertir una colección no genérica en una colección genérica?¿Cuál es la mejor manera de convertir una colección no genérica en una colección genérica?

Mi implementación actual copia la colección no genérica a una matriz y luego opera sobre eso, pero me preguntaba si había una forma mejor.

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

Respuesta

10

La forma más sencilla es por lo general el método Cast extensión:

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

Tenga en cuenta que este es diferido y arroyos sus datos, por lo que no tienen una "colección" completa como tal - pero es una fuente de datos perfecta para consultas LINQ.

Cast se llama de forma automática si se especifica un tipo de la variable de rango en una expresión de consulta:

Así que para convertir la consulta por completo:

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

o

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

De hecho , no necesita llamar al OrderByDescending y luego al First aquí; solo desea el valor máximo, que es Max método te consigue. Aún mejor, se le permite especificar una proyección de un tipo de elemento de origen en el valor que está tratando de encontrar, por lo que se puede hacer sin el Select también:

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

Si usted tiene una colección que tiene alguna elementos del tipo correcto pero algunos que pueden no serlo, puede usar OfType en su lugar. Cast arroja una excepción cuando encuentra un artículo del tipo "incorrecto"; OfType simplemente lo salta.

+0

¡Muchas gracias! No estoy seguro de cómo me perdí ese método en la documentación, ¡pero eso es exactamente lo que estaba buscando! También gracias por la sugerencia sobre el uso de Max() – guhou

0
matches.Cast<Match>(); 
1

Puede usar Cast o OfType en un IEnumerable para convertir. Cast arrojará yeso ilegal si el elemento no se puede convertir al tipo indicado, mientras que OfType saltará cualquier elemento que no se pueda convertir.

Cuestiones relacionadas