2008-09-09 22 views
22

ich mich oft Code wie folgt zu schreiben finden:Console.WriteLine und generische Liste

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

Besser wäre so etwas wie dieses:

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

Ich vermute, es gibt einige clevere Art und Weise, dies zu tun, aber Ich sehe es nicht. Hat jemand eine bessere Lösung als der erste Block?

Antwort

52

tun:

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

EDIT: Um die anderen, die geantwortet haben - er sie alle auf der gleichen Linie, mit Tabs zwischen ihnen will. :)

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

edit: ahhh er hat mich dazu geschlagen.

+0

Beat Sie um etwa 30 Sekunden. :) –

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

Edit: Verdammt noch mal! hat zu lange gebraucht, um das Visual Studio zu öffnen, um es zu testen.

+2

Sie müssen relativ jung sein - wer braucht Visual Studio? Ich habe die CLR in meinem Kopf laufen. J/K –

15

Ein anderer Ansatz, nur für Kicks:

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

Schön - Mehr als eine Art, eine Katze zu häuten! –

+2

Es funktioniert bei mir nicht mit einer Liste . Ich habe InvalidCastException erhalten. –

+0

Ich erhielt auch 'InvalidCastException' - Antwort ist falsch. Außerdem dasselbe Ergebnis, wenn ich 'List ' mit impliziter und expliziter Umwandlung für 'CustomType' verwendet habe. – sergtk

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

Dann später ...

list.WriteLine(); 
3

neue Liste {1, 3, 5} .ForEach (Console.WriteLine);

3

Wenn es ein Stück Code gibt, den Sie die ganze Zeit wiederholen, wiederholen Sie es in Ihrer eigenen Bibliothek und rufen Sie das an. In diesem Sinne gibt es zwei Aspekte, um hier die richtige Antwort zu finden. Die erste ist Klarheit und Kürze im Code, der die Bibliotheksfunktion aufruft. Die zweite ist die Auswirkungen auf die Leistung von foreach.

Zuerst lassen Sie uns über die Klarheit und Kürze im aufrufenden Code nachdenken.

Sie können in einer Reihe von Möglichkeiten foreach tun:

  1. for-Schleife
  2. foreach Schleife
  3. Collection.ForEach

Aus all den Möglichkeiten, eine foreach Liste zu tun. ForEach mit einer Lamba ist die klarste und kurzeste.

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

Also in diesem Stadium kann es wie die Liste aussehen. Für jeden ist der Weg zu gehen. Wie ist die Leistung davon? Es stimmt, dass in diesem Fall die Zeit für das Schreiben in die Konsole die Leistung des Codes bestimmt. Wenn wir etwas über die Leistung eines bestimmten Sprachmerkmals wissen, sollten wir es zumindest berücksichtigen.

Laut Duston Campbell's performance measurements of foreach ist der schnellste Weg zur Iteration der Liste unter optimiertem Code die Verwendung einer for-Schleife ohne Aufruf von List.Count.

Die for-Schleife ist jedoch ein ausführliches Konstrukt. Es wird auch als ein sehr iterativer Weg gesehen, Dinge zu tun, die nicht mit dem gegenwärtigen Trend zu funktionalen Idiomen übereinstimmen.

Also können wir Kürze, Klarheit und Leistung bekommen? Wir können mit einer Erweiterungsmethode arbeiten. In einer idealen Welt würden wir eine Erweiterungsmethode für Console erstellen, die eine Liste annimmt und sie mit einem Begrenzer schreibt. Dies ist nicht möglich, weil Console eine statische Klasse ist und Erweiterungsmethoden nur für Instanzen von Klassen funktionieren. Stattdessen müssen wir die Erweiterungsmethode auf die Liste setzen sich (laut David B Vorschlag):

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

Dieser Code an vielen Orten verwendet wird, so sollten wir folgende Verbesserungen durchführen:

  • Anstatt foreach zu verwenden, sollten wir den schnellsten Weg der Iteration der Sammlung verwenden, die eine for-Schleife mit einer zwischengespeicherten Zählung ist.
  • Derzeit kann nur List als Argument übergeben werden. Als Bibliotheksfunktion können wir sie mit geringem Aufwand verallgemeinern.
  • Verwenden von List beschränkt uns nur auf Listen, die Verwendung von IList ermöglicht diesen Code auch mit Arrays zu arbeiten.
  • Da die Extension-Methode auf eine IList wir müssen sein wird, den Namen ändern, um zu verdeutlichen, was wir schreiben an:

Hier ist, wie der Code für die Funktion aussehen würde:

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

Wir können dies noch weiter verbessern, indem wir dem Client erlauben, das Trennzeichen zu übergeben. Wir könnten dann eine zweite Funktion zur Verfügung stellen, die mit dem Standard-Trennzeichen wie diese zu trösten schreibt:

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

So, jetzt, da wir einen kurzen wollen, klare performante Art und Weise des Schreibens Listen an die Konsole wir eine haben. Hier gesamte Quellcode einschließlich einer Demonstration der Verwendung der die Bibliotheksfunktion:

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

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

Sie könnten denken, dass dies das Ende der Antwort sein sollte. Es gibt jedoch noch eine weitere Verallgemeinerung, die getan werden kann. Aus Fatcat's Frage geht nicht hervor, ob er immer an die Konsole schreibt. Vielleicht ist etwas anderes in der Zukunft zu tun. In diesem Fall wird die Antwort von Jason Bunting diese Allgemeinheit geben. Hier ist seine Antwort wieder:

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

Das heißt, wenn wir eine weitere Verfeinerung unserer Erweiterungsmethoden machen, und fügen Sie FastForEach wie folgt:

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

Dies ermöglicht es uns, einen beliebigen Code gegen jedes Element auszuführen in der Sammlung mit der schnellstmöglichen Iterationsmethode.

Wir können sogar die WriteToConsole Funktion ändern FastForEach

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

So, jetzt den gesamten Quellcode, darunter ein Beispiel für die Verwendung von FastForEach zu verwenden ist:

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

Das ist eine wirklich gute Antwort! Obwohl ich die Idee nicht mag, eine Erweiterungsmethode wie 'WriteToConsole' in einer generischen Liste zu haben. Dies verstößt eindeutig gegen das Muster der einheitlichen Verantwortlichkeit. Ich würde nicht erwarten, dass eine Liste irgendwelche Kenntnisse über die Konsole hat, sei es in ihrer Implementierung oder in einer Erweiterungsmethode. –

+0

wahr, ich denke, Ihre Wahl hängt davon ab, was Sie mögen und welche Sorge größer ist ... –

0

Auch können Sie treten:

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

string.Join funktioniert nicht mit einer Liste . –

+0

string.Join funktioniert tadellos mit einer Liste . –