N 個のオブジェクトのリストを zeros( 0.0 ) で開始したいと考えています。私はそれを次のようにすることを考えました:
var TempList = new List<float>(new float[(int)(N)]);
それを行うためのより良い(より効率的な)方法はありますか?
N 個のオブジェクトのリストを zeros( 0.0 ) で開始したいと考えています。私はそれを次のようにすることを考えました:
var TempList = new List<float>(new float[(int)(N)]);
それを行うためのより良い(より効率的な)方法はありますか?
現在のソリューションは、リストをゼロで初期化することのみを目的として配列を作成し、その配列を破棄します。これは効率的ではないように見えるかもしれません。ただし、後で説明するように、実際には非常に効率的です。
中間配列を作成しないメソッドを次に示します。
int n = 100;
var list = new List<float>(n);
for (int i = 0; i < n; ++i)
list.Add(0f);
または、次のように「n」回指定Enumerable.Repeat()
するために使用できます。0f
var list = new List<float>(n);
list.AddRange(Enumerable.Repeat(0f, n));
しかし、これらの方法はどちらも遅くなります。
これは、いくつかのタイミングを行うための小さなテストアプリです。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Demo
{
public class Program
{
private static void Main()
{
var sw = new Stopwatch();
int n = 1024*1024*16;
int count = 10;
int dummy = 0;
for (int trial = 0; trial < 4; ++trial)
{
sw.Restart();
for (int i = 0; i < count; ++i)
dummy += method1(n).Count;
Console.WriteLine("Enumerable.Repeat() took " + sw.Elapsed);
sw.Restart();
for (int i = 0; i < count; ++i)
dummy += method2(n).Count;
Console.WriteLine("list.Add() took " + sw.Elapsed);
sw.Restart();
for (int i = 0; i < count; ++i)
dummy += method3(n).Count;
Console.WriteLine("(new float[n]) took " + sw.Elapsed);
Console.WriteLine("\n");
}
}
private static List<float> method1(int n)
{
var list = new List<float>(n);
list.AddRange(Enumerable.Repeat(0f, n));
return list;
}
private static List<float> method2(int n)
{
var list = new List<float>(n);
for (int i = 0; i < n; ++i)
list.Add(0f);
return list;
}
private static List<float> method3(int n)
{
return new List<float>(new float[n]);
}
}
}
RELEASE ビルドの結果は次のとおりです。
Enumerable.Repeat() took 00:00:02.9508207
list.Add() took 00:00:01.1986594
(new float[n]) took 00:00:00.5318123
したがって、中間配列を作成する方がはるかに高速であることがわかります。ただし、このテスト コードには欠陥があることに注意してください。これは、中間配列の割り当てによって発生するガベージ コレクションのオーバーヘッドが考慮されていないためです (適切なタイミングを取るのは非常に困難です)。
最後に、リフレクションを使用してこれを最適化できる、本当に悪質で厄介な方法があります。しかし、これは脆弱であり、将来的には機能しなくなる可能性が高く、製品コードでは絶対に使用しないでください。
ここでは、好奇心としてのみ提示します。
private static List<float> method4(int n)
{
var list = new List<float>(n);
list.GetType().GetField("_size", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(list, n);
return list;
}
これを行うと、0.5 秒かかる 2 番目に速い方法と比較して、時間が 10 分の 1 秒未満に短縮されます。しかし、それをしないでください。
何が問題なの
float[] A = new float[N];
また
List<float> A = new List<float>(N);
コンパイラを細かく管理しようとすることは最適化ではないことに注意してください。必要なことを行う最もクリーンなコードから始めて、コンパイラーに任せてください。
編集 1
のソリューションList<float>
は、内部N
アイテムのみが初期化された空のリストを生成します。だから私たちはいくつかの反射でそれをだますことができます
static void Main(string[] args)
{
int N=100;
float[] array = new float[N];
List<float> list=new List<float>(N);
var size=typeof(List<float>).GetField("_size", BindingFlags.Instance|BindingFlags.NonPublic);
size.SetValue(list, N);
// Now list has 100 zero items
}
なぜだめですか:
var itemsWithZeros = new float[length];