2009-05-26 33 views
12

Teniendo en cuenta la variableCómo crear una lista <T> a partir de una cadena separada por comas?

string ids = Request.QueryString["ids"]; // "1,2,3,4,5"; 

¿Hay alguna manera de convertirlo en una lista sin hacer algo como

List<int> myList = new List<int>(); 

foreach (string id in ids.Split(',')) 
{ 
    if (int.TryParse(id)) 
    { 
     myList.Add(Convert.ToInt32(id)); 
    } 
} 
+0

¿Puede especificar el comportamiento que desea por favor - se trata sólo de que el anterior, es decir, en silencio ignoran los bits que no son Int32s? Ninguna de las respuestas está tomando eso en cuenta ... –

+0

Estoy ignorando silenciosamente las identificaciones erróneas porque las escriben los editores de contenido que quieren incluir ciertas imágenes en sus páginas, sin embargo, puedo poner la validación en el campo para detener eso. sucediendo, supongo –

+0

Sí, eso es exactamente lo que estaba insinuando ... –

Respuesta

47

para crear la lista desde cero, utilizar LINQ:

ids.Split(',').Select(i => int.Parse(i)).ToList(); 

Si ya tiene el objeto de lista, omita la llamada ToList() y utilizar AddRange:

myList.AddRange(ids.Split(',').Select(i => int.Parse(i))); 

Si algunas entradas en la cadena puede no ser enteros, puede utilizar TryParse:

método
int temp; 
var myList = ids.Split(',') 
    .Select(s => new { P = int.TryParse(s, out temp), I = temp }) 
    .Where(x => x.P) 
    .Select(x => x.I) 
    .ToList(); 

Una última (más lento) que evita temps/TryParse pero se salta las entradas no válidas es el uso de expresiones regulares:

var myList = Regex.Matches(ids, "[0-9]+").Cast<Match>().SelectMany(m => m.Groups.Cast<Group>()).Select(g => int.Parse(g.Value)); 

Sin embargo, esto puede tirar si una de las entradas desborda int (999999999999).

+0

Pero no es resistente (no hace un TryParse) .... –

+0

He editado mi respuesta para reflejar lo que se necesita para una implementación TryParse en línea. Aquí es donde una implementación de Convert.ToNullableInt32 sería útil :) – Jason

+0

Sí seguro de que compila (en LINQPad: D) –

3

Usando LINQ:

myList.AddRange(ids.Split(',').Select(s => int.Parse(s)); 

O directamente:

var myList = ids.Split(',').Select(s => int.Parse(s)); 

Además, para evitar que el compilador generar explícitamente la lambda (en gran medida redundante), considere:

var myList = ids.Split(',').Select((Func<string, int>)int.Parse); 

(Pista: micro-optimización.)

También hay TryParse que debe ser usado en lugar de Parse (sólo) si la entrada no válida es posible y debe manejarse en silencio. Sin embargo, otros han publicado soluciones usando TryParse así que ciertamente no lo haré. Solo tenga en cuenta que no debe duplicar el cálculo.

+2

De esta manera se obtiene una lista de booleanos. Int32.TryParse devuelve un booleano. –

+0

Otro problema con los últimos 2 ejemplos es que devuelven IEnumerable kastermester

+1

@Konrad, entré y lo arreglé para usted. Espero que no te importe;) – LukeH

7

Esto debe hacer el truco:

myList.Split(',').Select(s => Convert.ToInt32(s)).ToList(); 

Si la lista puede contener otros datos además de los números enteros, una llamada TryParse deben ser incluidos. Ver la respuesta aceptada.

+0

igual que aceptado? –

+0

Correcto, creo que se nos ocurrió la misma respuesta al mismo tiempo ... –

+0

Bueno, entonces, el mismo comentario no está utilizando TryParse: P (Pero deshacer -1!) –

1

Un problema que tenemos aquí es cómo vamos a tratar con valores que no son enteros (supongamos que obtendremos algunos que no son enteros). Una idea podría ser simplemente usar una expresión regular:

^- [0-9] + $

Ahora, podemos combinar todo esto con (como se muestra en el ejemplo de Konrad):?

var myList = ids.Split(',').Where(s => Regex.IsMatch(s, "^-?[0-9]$")).Select(s => Convert.ToInt32(s)).ToList(); 

Eso debería hacer el trabajo.

+0

Regex no dice [1-9] +, pero si lo hiciera, aún podría estar fuera de rango y arrojar, no lo mismo que tryparse. –

+0

Acerca de fuera de rango: muy cierto. Sin embargo, no veo por qué quiere cambiar la Regex a [1-9] +, esto convertiría el número "10" en un número no válido. También modificaré la expresión regular ligeramente para tener en cuenta los números negativos. – kastermester

+0

Lo siento, significaba [0-9], (realmente quise decir \ d). Solo estaba haciendo el alegato de "dos problemas", junto con señalar que el código es más complejo y differnet con regex. Su expresión regular todavía no tiene un "+" después del [0-9], por lo que solo funcionará con 1 dígito y, por lo tanto, nunca saldrá de Raqnge: P –

2

O incluyendo TryParse como en su ejemplo:

var res = ids.Split(',').Where(x => { int tmp; return int.TryParse(x, out tmp); }).Select(x => int.Parse(x)).ToList(); 
2

para que coincida con la petición formulada en términos de características y el comportamiento de rendimiento, se debe hacer lo mismo y no ir fuera de expresiones regulares doign o no hacer el 'TryParse' : -

ds.Split(',') 
    .Select(i => { 
    int value; 
    bool valid = int.TryParse(out value); 
    return new {valid, value} 
    }) 
    .Where(r=>r.valid) 
    .Select(r=>r.value) 
    .ToList(); 

Sin embargo, aunque correcta, eso es bastante feo: D

Préstamos de una pista en el comentario de Jason: -

ds.Split(',') 
    .Select(i => { 
    int value; 
    bool valid = int.TryParse(out value); 
    return valid ? new int?(value) : null; 
    }) 
    .Where(r=>r != null) 
    .Select(r=>r.Value) 
    .ToList(); 

O

static class Convert 
{ 
    public static Int32? ConvertNullable(this string s) 
    { 
    int value; 
    bool valid = int.TryParse(out value); 
    return valid ? new int?(value) : null; 
    } 
} 

ds.Split(',') 
    .Select(s => Convert.ConvertNullable(s)) 
    .Where(r=>r != null) 
    .Select(r=>r.Value) 
    .ToList(); 
+0

¡Esa es la solución correcta! – Dario

Cuestiones relacionadas