C#

C# ArrayListとList

.NET Frameworkに’ArrayList’と呼ばれるクラスがあります。
このクラスは「動的配列」と呼ばれ、要素を追加したり削除したりと操作が簡単にできるクラスです。

名前空間までつけると’System.Collections.ArrayList’クラスです。

とにかくArrayListを使ってみる

int count = 10000;
System.Collections.ArrayList lst = new System.Collections.ArrayList(count);

for(int i = 0; i < lst.Capacity; i++)
{
    // 要素に値を追加する
    lst.Add(i);
}

for(int i = 0; i < lst.Capacity; i++)
{
    // 値をリストから取り出す
    int a = (int)lst[i];
}

普通に使えます。

ただ、C++をやっている人はお気づきだと思いますが、「動的配列」なのにあるものがありません。
「格納するデータの型の指定」がないんです。

 

ArrayListに格納するデータの型は何?

答えは、object型です。
.NET Framework(C#)においては、すべての型はobject型の派生クラスになります。
これによりArrayListクラスというクラスが実現されています。

ところが、.NET Frameworkにはとても似たクラスがあります。

System.Collections.Generic.Listクラスです。
本当は System.Collections.Generic.List<T> (Tは格納するデータの型)と記述して使います。
(C++をやっている人にはこちらのほうがなじみやすいと思います)

 

同じ処理をSystem.Collections.Generic.Listで書いてみる

さきほどのソースと同じ処理を行うものをSystem.Collections.Generic.Listで書いたものです。

int count = 10000;
System.Collections.Generic.List<int> lst = new System.Collections.Generic.List<int>(count);

for(int i = 0; i < lst.Capacity; i++)
{
    // 要素に値を追加する
    lst.Add(i);
}

for(int i = 0; i < lst.Capacity; i++)
{
    // 値をリストから取り出す
    int a = (int)lst[i];
}

 

コードでの違いは1行です。

ここまで見るとint型と格納するデータの型を決めて格納することしかできない’System.Collections.Generic.List<int>’クラスと
なんでも格納できる’System.Collections.ArrayList’クラス、ここだけ見ると「どっちでも・・・」と
思うかもしれませんが、この2つのクラスは動かしてみると処理時間が全く異なります。

 

ArrayListとList<int>で処理時間を計測してみる

下記のコードで処理時間を計測してみました。

static void Main(string[] args)
{
    int count = 10000;
    Stopwatch sw = new Stopwatch();

    //
    // ArrayListで処理時間を計測する
    //
    System.Collections.ArrayList lst1 = new System.Collections.ArrayList(count);

    sw.Start();
    for(int i = 0; i < lst1.Capacity; i++)
    {
        // 要素に値を追加する
        lst1.Add(i);
    }
    sw.Stop();

    Console.WriteLine(string.Format("ArrayList set Ticks:{0}", sw.ElapsedTicks));
    sw.Reset();

    sw.Start();
    for (int i = 0; i < lst1.Capacity; i++)
    {
        // 値をリストから取り出す
        int a = (int)lst1[i];
    }
    sw.Stop();

    Console.WriteLine(string.Format("ArrayList get Ticks:{0}", sw.ElapsedTicks));

    //
    // List<int>で処理時間を計測する
    //
    System.Collections.Generic.List<int> lst2 = new System.Collections.Generic.List<int>(count);

    sw.Start();
    for (int i = 0; i < lst2.Capacity; i++)
    {
        // 要素に値を追加する
        lst2.Add(i);
    }
    sw.Stop();

    Console.WriteLine(string.Format("List<int> set Ticks:{0}", sw.ElapsedTicks));
    sw.Reset();

    sw.Start();
    for (int i = 0; i < lst2.Capacity; i++)
    {
        // 値をリストから取り出す
        int a = (int)lst2[i];
    }
    sw.Stop();

    Console.WriteLine(string.Format("List<int> get Ticks:{0}", sw.ElapsedTicks));

    Console.ReadKey();
}

計測した結果です。

ArrayList List<int>
追加 1148 592 -556(List<int>のほうが速い)
取得 305 260 -45(List<int>のほうが速い)

※計測時の単位はTicks(CPUのカウント数)です。値が小さいほうが速いです。

 

けっこうな差が出ています。

理由は、System.Collections.ArrayListは

追加するときに、int型のオブジェクトをobject型にしてからリストに登録
取得するときに、object型のオブジェクトをリストから取り出してint型で取得

という動きをしています。

これに対して、System.Collections.Generic.List<int>は
追加するときに、int型のオブジェクトを登録
取得するときに、int型で取得

という動きなので、処理時間はSystem.Collections.Generic.List<int>のほうが短くなるということです。

 

タイトルとURLをコピーしました