2010-06-29 13 views
6

Si tengo, por ejemplo, la siguiente cadena:Shove una cadena delimitada en una lista <int>

"123; 3344; 4334; 12"

y quiero que estos números en un genérico List<int>, supongo que No sé de una buena manera aquí aparte de dividir en un bucle y hacer una conversión, luego agregar a un List<int> a través de cada iteración. ¿Alguien tiene otras formas de hacerlo?

Actualizado. Esto es lo que se me ocurrió. Quiero hacer esto a la vieja usanza, no con LINQ porque estoy tratando de mejorar con solo cadenas, matrices, listas y manipular y convertir en general.

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

Este es un nuevo método de utilidad cadena que va a utilizar cada vez que necesito para convertir una lista cadena delimitada a la lista

Así que estoy volviendo una lista vacía de nuevo a la persona que llama si algo falla. ¿Bueno malo? ¿Es bastante común hacer esto?

Sí, hay más formas "elegantes" que hacer esto con LINQ pero quiero hacerlo manually..the manera pasada por ahora sólo para mi propio entendimiento.

Además, lo que me molesta de esto:

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

es que no tengo ni idea:

  1. Cómo empujón en un TryParse allí en su lugar.
  2. ¿Y si el str.Split(';').Select(Int32.Parse) solo falla por cualquier razón ... entonces el método que esta AddRange reside en que va a estallar y, a menos agrego un try/catch alrededor de todo esto, estoy jodido si no lo hago manejarlo apropiadamente
+0

Usando TryParse aquí es un grave error: http://en.wikipedia.org/wiki/GIGO –

Respuesta

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, se lee el título! Sugiero usar TryParse en lugar de Parse. –

+0

Me preocupo si solo puede hacer la lista list = "123; 3344; 4334; 12" .Split (";"); Sé que puedes hacerlo con una matriz: string [] list = "123; 3344; 4334; 12" .Split (";"); – PositiveGuy

+1

@coffee, no. No se puede convertir implícitamente de una matriz de cadenas a una 'Lista '. Además, debe ser 'Split (';')'. Tenga en cuenta la comilla simple, porque es un carácter literal. –

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

Interlocutor señala:

no sé de una buena manera aquí aparte divide en un bucle y hacer una conversión a continuación, añadir a una lista

En general, esta es una de las principales razones por las que LINQ se introdujo en C# - para volver mueve la necesidad de trabajar con secuencias de valores implementando bucles, y en su lugar solo declaras tu intención de transformar la secuencia. Si alguna vez te encuentras pensando "No sé cómo hacer esto excepto con un bucle", es hora de buscar en un constructo LINQ que haga el trabajo por ti.

actualización de rendimiento:

Rendimiento de LINQ se ha quesioned a continuación. Mientras que en los comentarios la idea de LINQ siendo más lenta se defiende ya que obtener los beneficios de la legibilidad, mantenibilidad y composibility, hay otro aspecto que le da una ventaja de rendimiento LINQ fácil: el paralelismo. Aquí hay un ejemplo donde al agregar solo una llamada al método de extensión, AsParallel() se duplica el rendimiento. Este es un gran ejemplo de donde la escalabilidad mejora la micro-optimización sin siquiera tener que medir con mucho cuidado.Tenga en cuenta que no estoy afirmando que las micro optimizaciones nunca se necesiten, pero con las herramientas que tenemos disponibles en este nivel de abstración, la necesidad se hace infinitamente pequeña.

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

no paralelos: 00: 00: 07,0719911

paralelo: 00: 00: 04,5933906

+0

sí me pregunto sobre el rendimiento frente a la división estándar en un ciclo – PositiveGuy

+0

@coffeeaddict: es casi siempre insignificante, y solo se debe considerar para el cambio si se mide y se encuentra para ser un problema. He aquí una buena comparación reciente: http://jerrytech.blogspot.com/2010/02/revisiting-c-loop-performance.html – codekaizen

+0

No sé, siempre estoy aquí, puedes abusar de LINQ también en eso puede empezar a ser una peformance hog. No decir que estás equivocado ... 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)); 

He oído .Net 4.0 se ha añadido a ForEachEnumerable<T>, por lo que el ToList podría no ser necesario allí (no se puede probar).

+0

Después de 'ToList', tienes * una lista de entradas. El 'ForEach' no es necesario. –

+0

@Matthew Flaschen, de acuerdo. Mi pensamiento inicial (y ciertamente apresurado) inicial fue que la lista podría no ser original y podría ser necesario preservar el contenido. es decir, anexar los resultados a una lista existente sin reemplazo. –

-1

creo que esto es más simple

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

-1: Esto nunca funciona, porque no puedes convertir una cadena en un número entero. Solo puedes analizarlo (usando 'int.Parse()' o 'int.TryParse()'). – Oliver

Cuestiones relacionadas