2008-09-09 9 views
22

Je me retrouve souvent l'écriture de code comme ceci:Console.WriteLine et génériques Liste

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

mieux serait quelque chose comme ceci:

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

Je pense qu'il ya une façon intelligente de le faire, mais Je ne le vois pas. Est-ce que quelqu'un a une meilleure solution que le premier bloc?

Répondre

52

Faites ceci:

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

EDIT: Pour d'autres qui ont répondu - il les veut tous sur la même ligne, avec des onglets entre eux. :)

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

éditer: ahhh il m'a battu à elle.

+0

Vous battre d'environ 30 secondes. :) –

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

Edit: Bon sang! a pris trop de temps pour ouvrir le studio visuel pour le tester.

+2

Vous devez être relativement junior - qui a besoin de Visual Studio? J'ai le CLR dans ma tête. J/K –

15

Une approche différente, juste pour le plaisir:

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

Nice - Plus d'une façon de peler un chat! –

+2

Cela ne fonctionne pas pour moi avec une liste . J'ai InvalidCastException. –

+0

J'ai également obtenu 'InvalidCastException' - la réponse est incorrecte. De plus le même résultat quand j'ai essayé d'utiliser 'List ' avec une conversion implicite et explicite implémentée pour 'CustomType' – sergtk

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

Puis, plus tard ...

list.WriteLine(); 
3

nouvelle liste {1, 3, 5} .foreach (Console.WriteLine)

3

S'il y a un morceau de code que vous répétez tout le temps selon Do not Repeat Yourself, vous devriez le mettre dans votre propre bibliothèque et l'appeler. Dans cet esprit, il y a 2 aspects pour obtenir la bonne réponse ici. Le premier est la clarté et la brièveté du code qui appelle la fonction de bibliothèque. La seconde est les implications de performance de foreach.

D'abord, réfléchissons à la clarté et à la brièveté du code d'appel.

Vous pouvez faire foreach dans plusieurs façons:

  1. boucle
  2. boucle foreach
  3. Collection.ForEach

De toutes les façons de faire une liste de foreach. ForEach avec un lamba est le plus clair et le plus bref. Donc, à ce stade, il peut sembler que le List.ForEach est le chemin à parcourir. Cependant quelle est la performance de ceci? Il est vrai que dans ce cas le temps d'écriture sur la console va régir la performance du code. Lorsque nous savons quelque chose sur la performance d'une caractéristique particulière d'un langage, nous devrions au moins le considérer. La méthode la plus rapide pour parcourir la liste sous code optimisé est d'utiliser une boucle for sans appel à List.Count.

La boucle for est cependant une construction verbeuse. Il est également considéré comme une manière très itérative de faire les choses qui ne correspond pas à la tendance actuelle vers les idiomes fonctionnels.

Alors, pouvons-nous obtenir la brièveté, la clarté et la performance? Nous pouvons en utilisant une méthode d'extension. Dans un monde idéal, nous allons créer une méthode d'extension sur Console qui prend une liste et l'écrit avec un délimiteur. Nous ne pouvons pas le faire car la console est une classe statique et les méthodes d'extension ne fonctionnent que sur les instances de classes. Au lieu de cela nous avons besoin de mettre la méthode d'extension sur la liste elle-même (selon la suggestion de David B):

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

Ce code va utilisé dans de nombreux endroits que nous devons mener à bien les améliorations suivantes:

  • Au lieu d'utiliser foreach, nous devrions utiliser le moyen le plus rapide d'itérer la collection qui est une boucle for avec un nombre mis en cache.
  • Actuellement, seule la liste peut être passée en argument. En tant que fonction de bibliothèque, nous pouvons la généraliser en faisant un petit effort.
  • L'utilisation de la liste nous limite aux listes. L'utilisation de IList permet à ce code de fonctionner également avec les tableaux.
  • Puisque la méthode d'extension sera sur un IList nous devons changer le nom pour le rendre plus clair ce que nous écrivons:

Voici comment le code de la fonction regarderais:

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

Nous pouvons encore améliorer cela en permettant au client de passer dans le délimiteur. Nous pourrions alors fournir une seconde fonction qui écrit à la console avec le séparateur standard comme ceci:

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

Alors maintenant, étant donné que nous voulons une brève, claire façon des listes performante écriture à la console que nous avons un. Voici tout le code source, y compris une démonstration de l'utilisation de la fonction de la bibliothèque:

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

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

Vous pourriez penser que cela devrait être la fin de la réponse. Cependant, il y a un autre élément de généralisation qui peut être fait. La question de fatcat n'est pas claire s'il écrit toujours sur la console. Peut-être que quelque chose d'autre doit être fait dans le foreach. Dans ce cas, la réponse de Jason Bunting va donner cette généralité. Voici sa réponse encore:

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

C'est à moins de faire un plus de raffinement à nos méthodes d'extension et d'ajouter FastForEach comme ci-dessous:

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

Cela nous permet d'exécuter un code arbitraire contre tous les éléments dans la collection en utilisant la méthode d'itération la plus rapide possible.

On peut même changer la fonction WriteToConsole utiliser FastForEach

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

Alors maintenant l'intégralité du code source, y compris un exemple d'utilisation de FastForEach est:

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

Ceci est une très bonne réponse! Bien que je vois n'aime pas l'idée d'avoir une méthode d'extension comme «WriteToConsole» à une liste générique. Cela viole clairement le modèle de responsabilité unique. Je ne m'attendrais pas à ce qu'une liste ait des connaissances sur la console, que ce soit dans son implémentation ou dans une méthode d'extension. –

+0

vrai, je suppose que votre choix dépend de ce que vous aimez et quelle préoccupation est plus grande ... –

0

vous pouvez également faire rejoindre:

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

chaîne.Join ne fonctionne pas avec une liste . –

+0

string.Join fonctionne parfaitement bien avec une liste . –

Questions connexes