2009-05-26 3 views
12

Data la variabileCome creare un elenco <T> da una stringa separata da virgole?

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

Esiste un modo per convertirlo in un elenco senza fare qualcosa di simile a

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

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

è possibile specificare il comportamento desiderato si prega - è solo come sopra, vale a dire, in silenzio ignorano i bit che non sono Int32s? Nessuna delle risposte sta prendendo in considerazione questo ... –

+0

Sto silenziosamente ignorando id cattivi perché sono inseriti dagli editor di contenuti che vogliono inserire determinate immagini nelle loro pagine, tuttavia posso mettere la convalida sul campo per impedirglielo succede suppongo –

+0

Sì, questo è esattamente quello che stavo suggerendo a ... –

risposta

47

Per creare la lista da zero, utilizzare LINQ:

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

Se hai già l'oggetto lista, omettere la chiamata ToList() e utilizzare AddRange:

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

Se alcune voci la stringa non può essere interi, è possibile utilizzare TryParse: metodo che evita temps

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

Un ultimo (più lento)/TryParse ma salta voci non valide è quello di utilizzare Regex:

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

Tuttavia, questo può gettare se uno dei vostri voci trabocca int (999.999.999.999).

+0

Ma non è resiliente (non fa un TryParse) .... –

+0

Ho modificato la mia risposta per riflettere su cosa è necessario per un'implementazione TryParse in linea. È qui che sarebbe utile l'implementazione di Convert.ToNullableInt32 :) – Jason

+0

Sì, sicuro che compila (in LINQPad: D) –

3

utilizzando LINQ:

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

O direttamente:

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

Inoltre, per evitare che il compilatore di generare esplicitamente lambda (largamente ridondante), considerare:

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

(suggerimento: micro-ottimizzazione.)

C'è anche TryParse che dovrebbe essere usato al posto di Parse (solo) se l'input non valido è possibile e deve essere gestito in silenzio. Tuttavia, altri hanno pubblicato soluzioni usando TryParse quindi certamente non lo farò. Ricorda che non devi duplicare il calcolo.

+2

In questo modo si ottiene un elenco di valori booleani. Int32.TryParse restituisce un valore booleano. –

+0

Un altro problema con gli ultimi 2 esempi è in realtà che restituiscono IEnumerable kastermester

+1

@Konrad, ho saltato dentro e risolto quello per voi. Spero non ti dispiaccia;) – LukeH

7

Questo dovrebbe fare il trucco:

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

Se l'elenco può contenere altri dati oltre a numeri interi, una chiamata TryParse dovrebbe essere inclusa. Vedi la risposta accettata.

+0

uguale a quello accettato? –

+0

Corretto, pensiamo che sia venuta fuori la stessa risposta allo stesso tempo ... –

+0

Bene, lo stesso commento non sta usando TryParse: P (Ma annullando -1!) –

1

Un problema a portata di mano qui è il modo in cui tratteremo i valori che non sono numeri interi (assumiamo che ne otterremo alcuni che non sono numeri interi). Un'idea potrebbe essere usare semplicemente una regex:

^- [0-9] + $

Ora, potremmo combinare tutto questo con (come mostrato nell'esempio di Konrad):?

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

Questo dovrebbe fare il lavoro.

+0

Regex non sta dicendo [1-9] +, ma se lo facesse, potrebbe ancora essere fuori portata e lanciare - non lo stesso di tryparse. –

+0

Informazioni fuori dal raggio d'azione - molto vero. Tuttavia, non vedo perché vuoi cambiare il Regex in [1-9] +, questo trasformerebbe il numero "10" in un numero non valido. Inoltre modifico leggermente l'espressione regolare per tenere conto dei numeri negativi. – kastermester

+0

Mi spiace, intendevo [0-9], (intendevo veramente \ d). Stavo facendo solo l'accusa "due problemi", insieme a sottolineare che il codice è più complesso e differnet con regex. La tua regex non ha ancora un "+" dopo [0-9], quindi funzionerà solo con 1 cifra e quindi non uscirà mai da raqnge: P –

2

o comprendente TryParse come nel tuo esempio:

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

per abbinare la richiesta in termini di prestazioni e di comportamento, che dovrebbe fare la stessa cosa e non andare fuori espressioni regolari doign o non fare il '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(); 

Ma mentre corretto, che è abbastanza brutto: D

Prendendo in prestito da un accenno di commento di 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

Questa è la soluzione corretta! – Dario