2010-06-29 16 views
6

Se ho ad esempio, la seguente stringa:spingere una stringa delimitata in una lista <int>

"123; 3344; 4334; 12"

e voglio questi numeri in un generico List<int>, mi sa che non so di un buon modo qui oltre a dividere in un ciclo e fare una conversione quindi aggiungere a un List<int> attraverso ogni iterazione. Qualcuno ha altri modi per farlo?

Aggiornato. Ecco cosa mi è venuto in mente. Voglio farlo alla vecchia maniera, non con LINQ perché sto cercando di migliorare con solo stringhe, array, liste e manipolazioni e conversioni in generale.

public List<int> StringToList(string stringToSplit, char splitDelimiter) 
{ 
    List<int> list = new List<int>(); 

    if (string.IsNullOrEmpty(stringToSplit)) 
     return list; 

    string[] values = stringToSplit.Split(splitDelimiter); 

    if (values.Length <= 1) 
     return list; 

    foreach (string s in values) 
    { 
     int i; 
     if (Int32.TryParse(s, out i)) 
      list.Add(i); 
    } 

    return list; 
} 

Questo è un nuovo metodo di utilità stringa Ho intenzione di utilizzare ogni volta che ho bisogno di convertire un elenco stringa delimitata to List

Così sto tornando una lista vuota al chiamante se qualcosa non funziona. Buono cattivo? è abbastanza comune farlo?

Sì, ci sono più modi "eleganti" per farlo con LINQ ma voglio farlo manualmente .. al vecchio modo per ora solo per la mia comprensione.

Inoltre, quello che mi preoccupa di questo:

list.AddRange(str.Split(';').Select(Int32.Parse)); 

è che non ho idea:

  1. Come a spingere in un TryParse là invece.
  2. E se lo str.Split(';').Select(Int32.Parse) fallisce per qualsiasi motivo ... allora il metodo su cui si trova questo AddRange sta per esplodere e se non aggiungo un try/catch a questa cosa, sono fregato se non lo faccio gestirlo correttamente.
+0

Utilizzando TryParse ecco un grave errore: http://en.wikipedia.org/wiki/GIGO –

risposta

5
string str = "123;3344;4334;12"; 
List<int> list = new List<int>(); 

foreach (string s in str.Split(';')) 
{ 
    list.Add(Int32.Parse(s)); 
} 
+1

+1, avete letto il titolo! Suggerirei di utilizzare TryParse anziché Parse. –

+0

I ferito se si può semplicemente fare Elenco list = "123; 3344; 4334; 12" .Split (";"); So che puoi con un array: string [] list = "123; 3344; 4334; 12" .Split (";"); – PositiveGuy

+1

@ caffè, no. Non è possibile convertire implicitamente da una serie di stringhe in un 'Elenco '. Inoltre, dovrebbe essere 'Split (';')'. Nota la citazione singola, perché è un personaggio letterale. –

3
List<int> list = (from numString in "123;3344;4334;12".Split(';') 
        select int.Parse(numString)).ToList(); 
6
static int? ToInt32OrNull(string s) 
{ 
    int value; 
    return (Int32.TryParse(s, out value)) ? value : default(int?);  
} 
// ... 
var str = "123;3344;4334;12"; 
var list = new List<int>(); 
list.AddRange(str.Split(';') 
       .Select(ToInt32OrNull) 
       .Where(i => i != null) 
       .Cast<int>()); 

Domanda Note:

non so di un buon modo qui non per dividere in un ciclo e fare una conversione quindi aggiungere a un elenco

In generale, questo è uno dei motivi principali per cui LINQ è stato portato in C# - per ri sposta la necessità di lavorare con sequenze di valori implementando cicli, e invece dichiara semplicemente la tua intenzione di trasformare la sequenza. Se ti ritrovi a pensare "Non so come farlo se non con un loop" - è il momento di esaminare un costrutto LINQ che farà il lavoro per te.

prestazioni di aggiornamento:

prestazioni di LINQ è stato quesioned sotto. Mentre nei commenti l'idea che LINQ sia più lento è difeso dal momento che otteniamo i vantaggi di leggibilità, manutenibilità e composibilità, c'è un altro aspetto che conferisce a LINQ un vantaggio in termini di prestazioni: il parallelismo. Ecco un esempio in cui l'aggiunta di una sola chiamata al metodo di estensione, AsParallel() raddoppia le prestazioni. Questo è un ottimo esempio di dove scale-out batte la micro-ottimizzazione senza nemmeno dover misurare con molta attenzione.Nota Non sto affermando che le micro-ottimizzazioni non sono mai necessarie, ma con gli strumenti che abbiamo a disposizione a questo livello di assenzio, il bisogno diventa incredibilmente piccolo.

class Program 
{ 
    private const int ElementCount = 10000000; 

    static void Main(string[] args) 
    { 
     var str = generateString(); 
     var stopwatch = new Stopwatch(); 

     var list1 = new List<int>(ElementCount); 
     var list2 = new List<int>(ElementCount); 

     var split = str.Split(';'); 

     stopwatch.Start(); 
     list1.AddRange(split 
          .Select(ToInt32OrNull) 
          .Where(i => i != null) 
          .Cast<int>()); 
     stopwatch.Stop(); 

     TimeSpan nonParallel = stopwatch.Elapsed; 

     stopwatch.Restart(); 

     list2.AddRange(split 
          .AsParallel() 
          .Select(ToInt32OrNull) 
          .Where(i => i != null) 
          .Cast<int>()); 

     stopwatch.Stop(); 

     TimeSpan parallel = stopwatch.Elapsed; 

     Debug.WriteLine("Non-parallel: {0}", nonParallel); 
     Debug.WriteLine("Parallel: {0}", parallel); 
    } 

    private static String generateString() 
    { 
     var builder = new StringBuilder(1048576); 
     var rnd = new Random(); 

     for (int i = 0; i < ElementCount; i++) 
     { 
      builder.Append(rnd.Next(99999)); 
      builder.Append(';'); 
     } 

     builder.Length--; 

     return builder.ToString(); 
    } 

    static int? ToInt32OrNull(string s) 
    { 
     int value; 
     return (Int32.TryParse(s, out value)) ? value : default(int?); 
    } 
} 

non paralleli: 00: 00: 07,0719911

parallelo: 00: 00: 04,5933906

+0

Sì, mi chiedo sulla performance rispetto alla divisione standard in un ciclo sebbene – PositiveGuy

+0

@coffeeaddict: è quasi sempre trascurabile, e dovrebbe essere preso in considerazione per il cambiamento se viene misurato e trovato sii un problema. Ecco un confronto recente e valido: http://jerrytech.blogspot.com/2010/02/revisiting-c-loop-performance.html – codekaizen

+0

Non so che io sempre qui puoi usare troppo LINQ anche in questo può iniziare a essere un maiale cattivo, non dicendo che hai torto ... sì – PositiveGuy

1
string myString = "123;3344;4334;12"; 
var ints = new List<int>(); 
(from s in myString.Split(';') 
select int.Parse()).ToList().ForEach(i=>ints.Add(i)); 

Ho sentito .Net 4.0 potrebbe essere aggiunto a ForEachEnumerable<T>, quindi il ToList potrebbe non essere necessario lì (non può testare).

+0

Dopo il 'ToList', tu * hai * una lista di ints. "ForEach" non è necessario. –

+0

@ Matthew Flaschen, d'accordo. Il mio pensiero iniziale (e certamente frettoloso) era che la lista non fosse originale e che il contenuto avrebbe potuto essere conservato. Ad esempio, aggiungere i risultati a un elenco esistente senza sostituzione. –

-1

credo che questo sia più semplice

var str = "123;3344;4334;12"; 
    var list = str.Split(';').ToList().Cast<int>(); 
+0

-1: non funziona mai, perché non è possibile eseguire il cast di una stringa su un numero intero. Puoi solo analizzarlo (usando 'int.Parse()' o 'int.TryParse()'). – Oliver

Problemi correlati