2008-09-09 14 views
22

frecuencia me encuentro escribiendo código como este:y la lista genérica

List<int> list = new List<int> { 1, 3, 5 }; 
foreach (int i in list) { 
    Console.Write("{0}\t", i.ToString()); } 
Console.WriteLine(); 

mejor sería algo como esto:

List<int> list = new List<int> { 1, 3, 5 }; 
Console.WriteLine("{0}\t", list); 

Sospecho que hay alguna forma inteligente de hacer esto, pero Yo no lo veo ¿Alguien tiene una mejor solución que el primer bloque?

Respuesta

52

hacer esto:

list.ForEach(i => Console.Write("{0}\t", i)); 

EDIT: Para otras personas que han respondido - él los quiere a todos en la misma línea, con las lengüetas entre ellos. :)

2
 List<int> a = new List<int>() { 1, 2, 3, 4, 5 }; 
     a.ForEach(p => Console.WriteLine(p)); 

edición: ahhh me adelantó.

+0

Te ganas por unos 30 segundos. :) –

2
list.ForEach(x=>Console.WriteLine(x)); 
2
List<int> list = new List<int> { 1, 3, 5 }; 
list.ForEach(x => Console.WriteLine(x)); 

Editar: Maldita sea! demoró demasiado para abrir el estudio visual y probarlo.

+2

Debe ser relativamente junior, ¿quién necesita Visual Studio? Tengo el CLR corriendo en mi cabeza. J/K –

15

Un enfoque diferente, sólo por diversión:

Console.WriteLine(string.Join("\t", list.Cast<string>().ToArray())); 
+1

Agradable - ¡Más de una manera de despellejar a un gato! –

+2

No funciona para mí con una lista . Tengo InvalidCastException. –

+0

También obtuve 'InvalidCastException' - la respuesta es incorrecta. Además, el mismo resultado cuando traté de usar 'List ' con la conversión implícita y explícita implementada para 'CustomType' – sergtk

0
public static void WriteLine(this List<int> theList) 
{ 
    foreach (int i in list) 
    { 
    Console.Write("{0}\t", t.ToString()); 
    } 
    Console.WriteLine(); 
} 

Luego, más tarde ...

list.WriteLine(); 
3

nueva lista {1, 3, 5} .ForEach (Console.WriteLine);

3

Si hay un fragmento de código que repites todo el tiempo de acuerdo con Do not Repeat Yourself deberías ponerlo en tu propia biblioteca y llamarlo. Con eso en mente, hay dos aspectos para obtener la respuesta correcta aquí. El primero es la claridad y la brevedad en el código que llama a la función de la biblioteca. El segundo son las implicaciones de rendimiento de foreach.

Primero pensemos en la claridad y brevedad en el código de llamada.

Usted puede hacer foreach en un número de maneras:

  1. bucle for
  2. bucle foreach
  3. Collection.ForEach

De todas las maneras de hacer una lista foreach. Porque cada uno con un lamba es el más claro y breve.

list.ForEach(i => Console.Write("{0}\t", i)); 

Así que en esta etapa puede ser similar a la List.ForEach es el camino a seguir. Sin embargo, ¿cuál es el rendimiento de esto? Es cierto que en este caso el tiempo para escribir en la consola regirá el rendimiento del código. Cuando sabemos algo sobre el rendimiento de una característica particular del lenguaje, al menos debemos considerarlo.

De acuerdo con Duston Campbell's performance measurements of foreach, la forma más rápida de iterar la lista con código optimizado es utilizando un bucle for sin una llamada a List.Count.

Sin embargo, for loop es una construcción prolija. También se lo ve como una forma muy iterativa de hacer las cosas que no coincide con la tendencia actual hacia expresiones idiomáticas funcionales.

Entonces, ¿podemos obtener brevedad, claridad y rendimiento? Podemos mediante un método de extensión. En un mundo ideal, creamos un método de extensión en la consola que toma una lista y la escribe con un delimitador. No podemos hacer esto porque Console es una clase estática y los métodos de extensión solo funcionan en instancias de clases. En su lugar tenemos que poner el método de extensión en la propia lista (según la sugerencia de David B):

public static void WriteLine(this List<int> theList) 
{ 
    foreach (int i in list) 
    { 
    Console.Write("{0}\t", t.ToString()); 
    } 
    Console.WriteLine(); 
} 

Este código se va a se utiliza en muchos lugares por lo que debemos llevar a cabo las siguientes mejoras:

  • En lugar de usar foreach, debemos usar la forma más rápida de iterar la colección, que es un ciclo for con un conteo en caché.
  • Actualmente, solo la Lista se puede pasar como argumento. Como función de biblioteca, podemos generalizarla mediante una pequeña cantidad de esfuerzo.
  • Usar la Lista nos limita a solo Listas, El uso de IList le permite a este código trabajar con Arrays también.
  • Dado que el método de extensión estará en un IList necesitamos cambiar el nombre para hacerlo más claro lo que estamos escribiendo a:

Así es como el código de la función se vería:

public static void WriteToConsole<T>(this IList<T> collection) 
{ 
    int count = collection.Count(); 
    for(int i = 0; i < count; ++i) 
    { 
     Console.Write("{0}\t", collection[i].ToString(), delimiter); 
    } 
    Console.WriteLine(); 
} 

Podemos mejorar esto aún más al permitir que el cliente pase el delimitador. entonces podríamos proporcionar una segunda función que escribe en la consola con el delimitador estándar de la siguiente manera:

public static void WriteToConsole<T>(this IList<T> collection) 
{ 
    WriteToConsole<T>(collection, "\t"); 
} 

public static void WriteToConsole<T>(this IList<T> collection, string delimiter) 
{ 
    int count = collection.Count(); 
    for(int i = 0; i < count; ++i) 
    { 
     Console.Write("{0}{1}", collection[i].ToString(), delimiter); 
    } 
    Console.WriteLine(); 
} 

Así que ahora, teniendo en cuenta que queremos un breve, clara manera performant de las listas de escritura a la consola tenemos una. Aquí está todo el código fuente incluyendo una demostración del uso de la función de la biblioteca:

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace ConsoleWritelineTest 
{ 
    public static class Extensions 
    { 
     public static void WriteToConsole<T>(this IList<T> collection) 
     { 
      WriteToConsole<T>(collection, "\t"); 
     } 

     public static void WriteToConsole<T>(this IList<T> collection, string delimiter) 
     { 
      int count = collection.Count(); 
      for(int i = 0; i < count; ++i) 
      { 
       Console.Write("{0}{1}", collection[i].ToString(), delimiter); 
      } 
      Console.WriteLine(); 
     } 
    } 

    internal class Foo 
    { 
     override public string ToString() 
     { 
      return "FooClass"; 
     } 
    } 

    internal class Program 
    { 

     static void Main(string[] args) 
     { 
      var myIntList = new List<int> {1, 2, 3, 4, 5}; 
      var myDoubleList = new List<double> {1.1, 2.2, 3.3, 4.4}; 
      var myDoubleArray = new Double[] {12.3, 12.4, 12.5, 12.6}; 
      var myFooList = new List<Foo> {new Foo(), new Foo(), new Foo()}; 
      // Using the standard delimiter /t 
      myIntList.WriteToConsole(); 
      myDoubleList.WriteToConsole(); 
      myDoubleArray.WriteToConsole(); 
      myFooList.WriteToConsole(); 
      // Using our own delimiter ~ 
      myIntList.WriteToConsole("~"); 
      Console.Read(); 
     } 
    } 
} 

============================ ===========================

Puede pensar que este debería ser el final de la respuesta. Sin embargo, hay una nueva generalización que se puede hacer. No queda claro por la pregunta de Fatcat si él siempre está escribiendo en la consola. Quizás hay algo más que hacer en el foreach. En ese caso, la respuesta de Jason Bunting va a dar esa generalidad. He aquí su respuesta de nuevo:

list.ForEach(i => Console.Write("{0}\t", i)); 

Eso es menos que hagamos una configuración más a nuestros métodos de extensión y añadimos FastForEach de la siguiente manera:

public static void FastForEach<T>(this IList<T> collection, Action<T> actionToPerform) 
    { 
     int count = collection.Count(); 
     for (int i = 0; i < count; ++i) 
     { 
      actionToPerform(collection[i]);  
     } 
     Console.WriteLine(); 
    } 

Esto nos permite ejecutar cualquier código arbitrario en contra de todos los elementos en la colección utilizando el método de iteración más rápido posible.

Podemos incluso cambiar la función WriteToConsole utilizar FastForEach

public static void WriteToConsole<T>(this IList<T> collection, string delimiter) 
{ 
    collection.FastForEach(item => Console.Write("{0}{1}", item.ToString(), delimiter)); 
} 

Así que ahora todo el código fuente, incluyendo un ejemplo de uso de FastForEach es:

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace ConsoleWritelineTest 
{ 
    public static class Extensions 
    { 
     public static void WriteToConsole<T>(this IList<T> collection) 
     { 
      WriteToConsole<T>(collection, "\t"); 
     } 

     public static void WriteToConsole<T>(this IList<T> collection, string delimiter) 
     { 
      collection.FastForEach(item => Console.Write("{0}{1}", item.ToString(), delimiter)); 
     } 

     public static void FastForEach<T>(this IList<T> collection, Action<T> actionToPerform) 
     { 
      int count = collection.Count(); 
      for (int i = 0; i < count; ++i) 
      { 
       actionToPerform(collection[i]);  
      } 
      Console.WriteLine(); 
     } 
    } 

    internal class Foo 
    { 
     override public string ToString() 
     { 
      return "FooClass"; 
     } 
    } 

    internal class Program 
    { 

     static void Main(string[] args) 
     { 
      var myIntList = new List<int> {1, 2, 3, 4, 5}; 
      var myDoubleList = new List<double> {1.1, 2.2, 3.3, 4.4}; 
      var myDoubleArray = new Double[] {12.3, 12.4, 12.5, 12.6}; 
      var myFooList = new List<Foo> {new Foo(), new Foo(), new Foo()}; 

      // Using the standard delimiter /t 
      myIntList.WriteToConsole(); 
      myDoubleList.WriteToConsole(); 
      myDoubleArray.WriteToConsole(); 
      myFooList.WriteToConsole(); 

      // Using our own delimiter ~ 
      myIntList.WriteToConsole("~"); 

      // What if we want to write them to separate lines? 
      myIntList.FastForEach(item => Console.WriteLine(item.ToString())); 
      Console.Read(); 
     } 
    } 
} 
+0

¡Esta es una muy buena respuesta! Aunque veo que no me gusta la idea de tener un método de extensión como 'WriteToConsole' en una lista genérica. Esto claramente viola el patrón de responsabilidad individual. No esperaría que una lista tenga ningún conocimiento sobre la consola, ya sea en su implementación o en un método de extensión. –

+0

cierto, supongo que su elección depende de lo que le gusta y que la preocupación es más grande ... –

0

También podemos hacer unirse a:

var qwe = new List<int> {5, 2, 3, 8}; 
Console.WriteLine(string.Join("\t", qwe)); 
+1

cadena.Join no funciona con una lista . –

+0

string.Join funciona perfectamente bien con una lista . –