Вопрос

Я часто ловлю себя на том, что пишу подобный код:

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

Лучше было бы что-то вроде этого:

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

Я подозреваю, что есть какой-то умный способ сделать это, но я его не вижу.У кого-нибудь есть лучшее решение, чем первый блок?

Это было полезно?

Решение

Сделай это:

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

Редактировать:Для других, кто ответил - он хочет, чтобы все они были в одной строке, с вкладками между ними.:)

Другие советы

Другой подход, просто для пущего эффекта:

Console.WriteLine(string.Join("\t", list));

Если есть фрагмент кода, который вы все время повторяете в соответствии с "Не повторяйтесь сами", вы должны поместить его в свою собственную библиотеку и вызвать это.Имея это в виду, есть 2 аспекта получения правильного ответа здесь.Первый - это ясность и краткость в коде, вызывающем библиотечную функцию.Второй - это влияние foreach на производительность.

Сначала давайте подумаем о ясности и краткости вызывающего кода.

Вы можете сделать foreach несколькими способами:

  1. для цикла
  2. цикл foreach
  3. Коллекция.ForEach

Из всех способов создать список foreach.Общение с ламбой является самым ясным и кратким.

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

Таким образом, на данном этапе это может выглядеть как Список.ForEach - это правильный путь.Однако какова эффективность этого?Это правда, что в этом случае время записи в консоль будет определять производительность кода.Когда мы что-то знаем о производительности той или иной языковой функции, мы, безусловно, должны, по крайней мере, рассмотреть ее.

Согласно Измерения производительности foreach от Дастона Кэмпбелла самый быстрый способ итерации списка в оптимизированном коде - это использование цикла for без вызова List .Count.

Однако цикл for является подробной конструкцией.Это также рассматривается как очень итеративный способ делать что-то, что не соответствует текущей тенденции к функциональным идиомам.

Итак, можем ли мы добиться краткости, ясности и производительности?Мы можем это сделать, используя метод расширения.В идеальном мире мы бы создали метод расширения на консоли, который принимает список и записывает его с разделителем.Мы не можем этого сделать, потому что Console - это статический класс, а методы расширения работают только с экземплярами классов.Вместо этого нам нужно поместить метод расширения в сам список (согласно предложению Дэвида Б.):

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

Этот код будет использоваться во многих местах, поэтому мы должны внести следующие улучшения:

  • Вместо использования foreach мы должны использовать самый быстрый способ повторения коллекции, который представляет собой цикл for с кэшированным количеством.
  • В настоящее время в качестве аргумента может быть передан только List.Как библиотечную функцию, мы можем обобщить ее, приложив небольшое количество усилий.
  • Использование List ограничивает нас только списками, использование IList позволяет этому коду работать и с массивами.
  • Поскольку метод расширения будет находиться в IList, нам нужно изменить имя, чтобы было понятнее, для чего мы пишем:

Вот как будет выглядеть код для этой функции:

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

Мы можем улучшить это еще больше, разрешив клиенту передавать разделитель.Затем мы могли бы предоставить вторую функцию, которая записывает данные в консоль со стандартным разделителем, подобным этому:

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

Итак, теперь, учитывая, что нам нужен краткий, понятный и производительный способ записи списков в консоль, у нас есть один.Вот полный исходный код, включая демонстрацию использования библиотечной функции:

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

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

Вы можете подумать, что на этом ответ должен заканчиваться.Однако есть еще одно обобщение, которое можно сделать.Из вопроса fatcat неясно, всегда ли он пишет в консоль.Возможно, что-то еще нужно сделать в foreach.В этом случае ответ Джейсона Бантинга придаст такую общность.Вот его ответ еще раз:

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

Это если только мы не внесем еще одно уточнение в наши методы расширения и не добавим FastForEach, как показано ниже:

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

Это позволяет нам выполнять любой произвольный код для каждого элемента в коллекции используя как можно более быстрый итерационный метод.

Мы даже можем изменить функцию WriteToConsole на использование FastForEach

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

Итак, теперь весь исходный код, включая пример использования FastForEach, является:

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

новый список { 1, 3, 5 }.ForEach(консоль.Строка записи);

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

Редактировать:а-а-а, он опередил меня в этом.

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

Редактировать:Черт возьми!потребовалось слишком много времени, чтобы открыть Visual Studio и протестировать его.

Также вы можете присоединиться:

var qwe = new List<int> {5, 2, 3, 8};
Console.WriteLine(string.Join("\t", qwe));
public static void WriteLine(this List<int> theList)
{
  foreach (int i in list)
  {
    Console.Write("{0}\t", t.ToString());
  }
  Console.WriteLine();
}

Потом, позже...

list.WriteLine();
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top