C#.NET と VB.NET で厳密に型指定されたジェネリック List を反復処理する最良の方法は何ですか?
7 に答える
C# の場合:
foreach(ObjectType objectItem in objectTypeList)
{
// ...do some stuff
}
Purple Antの VB.NET に対する回答:
For Each objectItem as ObjectType in objectTypeList
'Do some stuff '
Next
IEnumerable の一般的な実装では、最善の方法は次のとおりです。
//C#
foreach( var item in listVariable) {
//do stuff
}
ただし、重要な例外があります。IEnumerable には、foreach ループが実際にコンパイルされるものである Current() と MoveNext() のオーバーヘッドが含まれます。
構造体の単純な配列がある場合:
//C#
int[] valueTypeArray;
for(int i=0; i < valueTypeArray.Length; ++i) {
int item = valueTypeArray[i];
//do stuff
}
速いです。
アップデート
@Steven Sudit (コメントを参照) との議論に続いて、私の元のアドバイスは古くなっているか間違っている可能性があると思うので、いくつかのテストを実行しました。
// create a list to test with
var theList = Enumerable.Range(0, 100000000).ToList();
// time foreach
var sw = Stopwatch.StartNew();
foreach (var item in theList)
{
int inLoop = item;
}
Console.WriteLine("list foreach: " + sw.Elapsed.ToString());
sw.Reset();
sw.Start();
// time for
int cnt = theList.Count;
for (int i = 0; i < cnt; i++)
{
int inLoop = theList[i];
}
Console.WriteLine("list for : " + sw.Elapsed.ToString());
// now run the same tests, but with an array
var theArray = theList.ToArray();
sw.Reset();
sw.Start();
foreach (var item in theArray)
{
int inLoop = item;
}
Console.WriteLine("array foreach: " + sw.Elapsed.ToString());
sw.Reset();
sw.Start();
// time for
cnt = theArray.Length;
for (int i = 0; i < cnt; i++)
{
int inLoop = theArray[i];
}
Console.WriteLine("array for : " + sw.Elapsed.ToString());
Console.ReadKey();
そのため、すべての最適化を行ってリリースでこれを実行しました。
list foreach: 00:00:00.5137506
list for : 00:00:00.2417709
array foreach: 00:00:00.1085653
array for : 00:00:00.0954890
そして、最適化せずにデバッグします:
list foreach: 00:00:01.1289015
list for : 00:00:00.9945345
array foreach: 00:00:00.6405422
array for : 00:00:00.4913245
したがって、かなり一貫しているように見え、一般的なリストよりも配列の方が高速ですfor
。foreach
ただし、これは 1 億回の繰り返しであり、最速の方法と最も遅い方法の差は約 0.4 秒です。大規模なパフォーマンス クリティカルなループを実行していない限り、心配する必要はありません。
C#
myList<string>().ForEach(
delegate(string name)
{
Console.WriteLine(name);
});
匿名デリゲートは現在 VB.Net に実装されていませんが、C# と VB.Net の両方でラムダを実行できるはずです。
C#
myList<string>().ForEach(name => Console.WriteLine(name));
VB.Net
myList(Of String)().ForEach(Function(name) Console.WriteLine(name))
Grauenwolf が指摘したように、ラムダは値を返さないため、上記の VB はコンパイルされません。他の人が示唆しているように、通常の ForEach ループはおそらく今のところ最も簡単ですが、通常どおり、C# で実行できることを 1 行で実行するにはコードのブロックが必要です。
これが役立つ理由の簡単な例を次に示します。これにより、IEnumerable が存在する場所以外の別のスコープからループ ロジックを渡すことができるため、必要がなければ公開する必要さえありません。
絶対にしたい相対 URL パスのリストがあるとします。
public IEnumerable<String> Paths(Func<String> formatter) {
List<String> paths = new List<String>()
{
"/about", "/contact", "/services"
};
return paths.ForEach(formatter);
}
したがって、次の方法で関数を呼び出すことができます。
var hostname = "myhost.com";
var formatter = f => String.Format("http://{0}{1}", hostname, f);
IEnumerable<String> absolutePaths = Paths(formatter);
この特定の例では、明らかにこれを達成するためのより良い方法があります"http://myhost.com/about", "http://myhost.com/contact"
。基本的な原則を実証しようとしています。
VB.NET の場合:
For Each tmpObject as ObjectType in ObjectTypeList
'Do some stuff '
Next
アプリケーションによって異なります。
- forループ、効率が優先される場合
- foreachループまたはForEachメソッドのいずれか、意図をより明確に伝えます
リストの内部実装を知らなくても、通常、リストを反復処理する最良の方法は foreach ループだと思います。foreach は IEnumerator を使用してリストを走査するため、オブジェクトからオブジェクトへの移動方法を決定するのはリスト自体です。
たとえば、内部実装がリンクされたリストである場合、単純な for ループは foreach よりもかなり遅くなります。
それは理にかなっていますか?
何かが足りないかもしれませんが、以下の例を使用すれば、一般的なリストを反復処理するのはかなり簡単です。List<> クラスは IList および IEnumerable インターフェイスを実装しているため、基本的に好きな方法で簡単に反復処理できます。
最も効率的な方法は、for ループを使用することです。
for(int i = 0; i < genericList.Count; ++i)
{
// Loop body
}
foreach ループを使用することもできます。
foreach(<insertTypeHere> o in genericList)
{
// Loop body
}