Konsola.WriteLine i lista generyczna

Często znajduję się pisząc kod w ten sposób:

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

Lepiej byłoby coś takiego:

List<int> list = new List<int> { 1, 3, 5 };
Console.WriteLine("{0}\t", list);
Podejrzewam, że jest na to jakiś sprytny sposób, ale tego nie widzę. Czy ktoś ma lepsze rozwiązanie niż pierwszy blok?
Author: Community, 2008-09-10

9 answers

Zrób to:

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

EDIT: do innych, którzy odpowiedzieli-chce je wszystkie w tej samej linii, z zakładkami między nimi. :)

 61
Author: Jason Bunting,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-09 21:22:46

Inne podejście, tylko dla kopniaków:

Console.WriteLine(string.Join("\t", list.Cast<string>().ToArray()));
 16
Author: Vinko Vrsalovic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-09 21:33:04

Nowa Lista { 1, 3, 5 }.ForEach (Konsol.WriteLine);

 3
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-20 12:01:10

Jeśli istnieje fragment kodu, który powtarzasz cały czas zgodnie z Don ' t Repeat Yourself, powinieneś umieścić go we własnej bibliotece i zadzwonić do niego. Mając to na uwadze, istnieją 2 aspekty uzyskania właściwej odpowiedzi tutaj. Pierwszą z nich jest jasność i zwięzłość w kodzie, który wywołuje funkcję biblioteki. Drugi to implikacje wydajnościowe foreach.

Najpierw pomyślmy o jasności i zwięzłości kodu wywołującego.

Możesz zrobić foreach w kilku sposoby:

  1. dla pętli
  2. pętla foreach
  3. Kolekcja.ForEach

Ze wszystkich sposobów na zrobienie listy foreach.Przedplecze z lambą jest Najczystsze i najmniejsze.

list.ForEach(i => Console.Write("{0}\t", i));
Więc na tym etapie może to wyglądać jak lista.ForEach jest najlepszą drogą. Ale co to za wydajność? To prawda, że w tym przypadku czas na napisanie do konsoli będzie regulował wydajność kodu. Gdy wiemy coś o wydajności danego języka cecha powinniśmy przynajmniej rozważyć.

Zgodnie zpomiary wydajności foreach najszybszym sposobem iteracji listy pod zoptymalizowanym kodem jest użycie pętli for bez wywołania listy.Licz.

Pętla for jest jednak konstrukcją wyrazistą. Postrzegany jest również jako bardzo iteracyjny sposób robienia rzeczy, który nie pasuje do obecnego trendu w kierunku idiomów funkcjonalnych.

Więc możemy uzyskać zwięzłość, jasność i wydajność? Możemy za pomocą metody rozszerzenia. W idealnym świecie stworzylibyśmy metodę rozszerzenia na konsoli, która pobiera listę i zapisuje ją za pomocą ogranicznika. Nie możemy tego zrobić, ponieważ Console jest klasą statyczną, a metody rozszerzenia działają tylko na instancjach klas. Zamiast tego musimy umieścić metodę rozszerzenia na samej liście (zgodnie z sugestią Davida B):

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

Ten kod będzie używany w wielu miejscach, więc powinniśmy wprowadzić następujące ulepszenia:

  • zamiast używać foreach powinniśmy użyć najszybszego sposobu iteracji zbioru, którym jest pętla for z liczbą buforowaną.
  • obecnie tylko lista może być przekazywana jako argument. Jako funkcję biblioteczną możemy ją uogólnić przy niewielkim wysiłku.
  • używanie List ogranicza nas tylko do list, użycie IList pozwala również na pracę z tablicami.
  • ponieważ metoda rozszerzenia będzie na iliście, musimy zmienić nazwę, aby była jaśniejsza, co piszemy do:

Oto jak wyglądałby kod dla funkcji:

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

Możemy to jeszcze poprawić, pozwalając klientowi przejść w ograniczniku. Możemy wtedy podać drugą funkcję, która zapisuje do konsoli za pomocą standardowego ogranicznika w następujący sposób:

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

Więc teraz, biorąc pod uwagę, że chcemy krótki, przejrzysty sposób pisania list do konsoli mamy jeden. Oto cały kod źródłowy wraz z demonstracją korzystania z biblioteki funkcja:

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

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

Można by pomyśleć, że to powinien być koniec odpowiedzi. Istnieje jednak dalsze uogólnienie, które można zrobić. Z pytania fatcata nie wynika, czy zawsze pisze do konsoli. Być może trzeba zrobić coś jeszcze w foreach. W takim razie odpowiedź Jasona Buntinga da taką ogólność. Oto znowu jego odpowiedź:

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

To chyba, że zrobimy jeden więcej udoskonaleń do naszych metod rozszerzenia i dodaj FastForEach jak poniżej:

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

Pozwala to na wykonanie dowolnego kodu z każdym elementem w kolekcji przy użyciu najszybszej możliwej metody iteracji.

Możemy nawet zmienić funkcję WriteToConsole na FastForEach

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

Więc teraz cały kod źródłowy, w tym przykładowe użycie FastForEach jest:

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();
        }
    }
}
 3
Author: Ed Sykes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-04 11:34:57
        List<int> a = new List<int>() { 1, 2, 3, 4, 5 };
        a.ForEach(p => Console.WriteLine(p));
Edit: ahhh wyprzedził mnie.
 2
Author: John Boker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-09 21:23:19
list.ForEach(x=>Console.WriteLine(x));
 2
Author: Mark Cidade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-09 21:23:33
List<int> list = new List<int> { 1, 3, 5 };
list.ForEach(x => Console.WriteLine(x));

Edit: Cholera! zbyt długo zajęło otwarcie visual studio, aby go przetestować.

 2
Author: George Mauer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-09 21:29:00
public static void WriteLine(this List<int> theList)
{
  foreach (int i in list)
  {
    Console.Write("{0}\t", t.ToString());
  }
  Console.WriteLine();
}
Więc, później...
list.WriteLine();
 0
Author: Amy B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 18:58:20

Możesz też dołączyć:

var qwe = new List<int> {5, 2, 3, 8};
Console.WriteLine(string.Join("\t", qwe));
 0
Author: Lev Lukomsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-06 23:42:17