質問

私はよく次のようなコードを書いていることに気づきます。

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

「Don't Reply Yourself」に従って常に繰り返すコードがある場合は、それを独自のライブラリに入れて呼び出す必要があります。それを念頭に置いて、ここで正しい答えを得るには 2 つの側面があります。1 つ目は、ライブラリ関数を呼び出すコードの明確さと簡潔さです。2 つ目は、foreach のパフォーマンスへの影響です。

まず、呼び出しコードの明確さと簡潔さについて考えてみましょう。

foreach はさまざまな方法で実行できます。

  1. forループ
  2. foreach ループ
  3. コレクション.ForEach

ランバを使用して foreach List.ForEach を実行するすべての方法の中で、最も明確で簡単な方法です。

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

したがって、この段階では List.ForEach が最適な方法のように見えるかもしれません。しかし、これの性能はどうなのでしょうか?確かに、この場合、コンソールに書き込む時間がコードのパフォーマンスを左右することになります。特定の言語機能のパフォーマンスについて何かがわかったら、少なくともそれを考慮する必要があります。

によると Duston Campbell による foreach のパフォーマンス測定 最適化されたコードでリストを反復する最速の方法は、List.Count を呼び出さずに for ループを使用することです。

ただし、for ループは冗長な構造です。また、これは物事を行うための非常に反復的な方法とも見なされており、関数型イディオムへの現在の傾向と一致しません。

それでは、簡潔さ、明瞭さ、パフォーマンスを実現できるでしょうか?拡張メソッドを使用することでそれが可能になります。理想的な世界では、リストを取得し、それを区切り文字で書き込む拡張メソッドを Console 上に作成します。Console は静的クラスであり、拡張メソッドはクラスのインスタンスでのみ機能するため、これを行うことはできません。代わりに、(David B の提案に従って) 拡張メソッドをリスト自体に追加する必要があります。

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

クライアントが区切り文字を渡せるようにすることで、これをさらに改善できます。次に、次のように標準の区切り文字を使用してコンソールに書き込む 2 番目の関数を提供できます。

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

これにより、コレクション内のすべての要素に対して任意のコードを実行できるようになります。 可能な限り最速の反復方法を使用する.

FastForEach を使用するように WriteToConsole 関数を変更することもできます。

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(Console.WriteLine);

        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