コレクション

コレクションとは

すでに学んだとおり、大量のデータを扱うときには、配列を使いました。しかし、配列には一つ欠点があります。それは、あらかじめ、格納するデータの数が決まっていることです。しかし、場合によっては、あらかじめどれだけのデータを格納するかわからない時があります。その時便利なのが、Collection(コレクション)です。

Collectionは、様々なデータ群を扱うクラス群です。ネームスペース「System.Collections.Generic」に含まれています。したがって、この中のクラスを使うためには、以下の宣言をする必要があります。

System.Collections.Genericの利用
using System.Collections.Generic;

「using」以下に、使用するクラス群が存在するネームスペースを記述します。前述のように、Collectionクラスは、「System.Collections.Generic」にあるので、この宣言が必要です。

List

サンプルプログラム

Collectionには、様々なクラスが存在しますが、手始めに、一番使用頻度の高い、List(リスト)クラスを使用する簡単なサンプルを紹介しましょう。以下のサンプルを入力し、実行してみてください。

プロジェクトSampleEx601/Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleEx601
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> a = new List<int>();
            //  値を順に挿入
            a.Add(3);
            a.Add(2);
            a.Add(1);
            //  1番目に4を挿入
            a.Insert(1, 4);
            for(int i = 0; i < a.Count ; i++){
                Console.WriteLine("a[{0}]={1} ", i,a[i]);
            }
        }
    }
}
実行結果
a[0]=3
a[1]=4
a[2]=2
a[3]=1

Listの宣言と生成

Listは、配列に似たCollectionのクラスです。配列との違いは、長さを自由に変えられることと、データを途中に挿入できる点にあります。利用方法は、以下のようになります。

Listの宣言と生成
List<型/クラス> (変数名) = new List<型/クラス>();

型/クラスには、int,double…といったような基本データ型や、任意のクラスを指定できます。このサンプルでは、int型のListを生成しています。生成した段階では、Listは、大きさが0のデータが何も入っていない配列になります。

Listへのデータの追加

生成したListクラスにデータを追加するためには、Add()メソッドを利用します。Addメソッドは、以下のように用います。

Addメソッドの利用
(オブジェクト名).Add(データ);

15から17行目で、Listであるaには、順次、1,2,3というデータが追加されます。データには0,1,2…というインデックスがついているため、この段階で、a[0]、a[1]、a[2]には、それぞれ1,2,3というデータが格納されています。

また、Listには、すでに生成された配列の途中に、データを挿入することが可能です。それを可能にしているのが、19行目で利用されている、Insertメソッドです。Insertメソッドは、指定したインデックスの後に、データを追加することができます。

Insertメソッドの利用
(オブジェクト名).Insert(インデックス,データ);

ここでは、1番目に値4を挿入しています。もともと1番目には、2が、2番目には3が格納されていましたが、1番目以降のデータは、この値が挿入されたために、一つずつインデックスが後ろにずれます。これにより、データのならび順は、3,4,2,1となります。(図6-1.参照)

図6-1.ListのAddメソッドと、Insertメソッドの働き
ListのAddメソッドと、Insertメソッドの働き

Listの出力

このようにして、代入されたデータは、配列と同じように扱うことが可能です。20行目から22行目で、aの値を出力しています。その際、20行目で、Countメソッドで、Listの中に入っているデータの数を取得し、それにより、値a[0]、a[1]、…の結果を出力しています。

Listの中のデータの削除

続いて、Listの中のデータを削除するサンプルを見てみましょう。

プロジェクトSampleEx602/Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleEx602
{
    class Program
    {
        static void Main(string[] args)
        {
            List<String> a = new List<String>();
            //  データを追加
            a.Add("Taro");
            a.Add("Hanako");
            a.Add("Jiro");
            a.Add("Kaoru");
            //  データを削除
            a.Remove("Taro");   //  "Taro"を削除
            a.RemoveAt(1);      //  1番目のデータを削除
            foreach (String s in a)
            {
                Console.WriteLine(s);
            }
        }
    }
}
実行結果
Hanako
Kaoru

ここでは、データを削除するメソッドとして、Removeメソッドと、RemoveAtメソッドを使用しています。Removeメソッドは、指定したデータを削除します。このサンプルでは、15行目~18行目で、データを追加しています。これにより、"Taro"、"Hanako"、"Jiro"、"Kaoru"というデータの配列が生成されます。

まず、20行目のRemove()メソッドで、"Taro"というデータが削除されます。これにより、データは、"Hanako"、"Jiro"、"Kaoru"になります。続いて、21行目のRemoveAt()メソッドで、インデックス1番目のデータを削除します。このとき、1番目のデータは"Jiro"ですから、残ったデータは、"Hanako"、"Kaoru"となるわけです。

最後に、このデータを22行目から25行目で、データをコンソール画面に出力しています。ここでは、foreachループを用いて出力しています。このように、Listのデータは、配列同様、foreachループを用いて全成分を出力することが可能です。

Listクラスの主要メソッド

なお、Listクラスには、以下のような主要なメソッドが存在します。Listクラスにはこのほかにもたくさんのメソッドがありますが、以下のものを利用すれば、たいていのことは可能です。

表5-1.Listクラスの主要メソッド
メソッド 働き
Reverse() 全体の要素の順序を反転させます。
Find() 指定されたデータを探し、最も小さいインデックスを返します。
Exists() 指定されたデータと同じものが存在するかどうかを調べます。
Clear() 全てのデータを削除します。
Sort() オブジェクトを並べ替えます。

ハッシュテーブルの利用

ハッシュテーブルとは

ハッシュテーブルは、コレクションの一種で、別名、連想記憶とも言います。これも、配列の一種ですが、通常の配列との違いは、配列が、0,1,2…といったような、数値の番号によるインデックスでデータを管理しているのに対し、キー(key)と値(value)のペアを保持しているという点にあります。

具体的な例を挙げると、たとえば、「Sunday」と言う言葉と、「日曜日」、「Monday」という言葉と「月曜日」というデータを結びつける、といったように、キーと、それを基に得られる値を関連付けた辞書のようなデータ構造がハッシュテーブルです。

サンプルプログラム

C#で、ハッシュテーブルを実現するクラスとして、Dictionaryクラスがあります。以下のサンプルを実行してみてください。

プロジェクトSampleEx603/Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleEx603
{
    class Program
    {
        static void Main(string[] args)
        {
            //  連想記憶クラスの生成
            Dictionary<String, String> capital = new Dictionary<String, String>();
            //  データの追加
            capital["日本"] = "東京";
            capital["イギリス"] = "ロンドン";
            capital["フランス"] = "パリ";
            capital["中国"] = "北京";
            Console.WriteLine("世界の首都");
            foreach (String s in capital.Keys)
            {
                Console.WriteLine("{0}の首都は{1}です。",s,capital[s]);
            }
        }
    }
}
実行結果
世界の首都
日本の首都は東京です。
イギリスの首都はロンドンです。
フランスの首都はパリです。
中国の首都は北京です。

Dictionaryクラスの宣言と生成

Dictionaryクラスの宣言と生成は、以下のように行います。

Dictionaryクラスの宣言と利用
Dictionary<キーの型/クラス, 値の型/クラス> (変数名) = new Dictionary<キーの型/クラス, 値の型/クラス>();

Arrayとの違いは、キーと値の両方の型を宣言する必要があるという点です。このサンプルでは、国名とその首都の名前と言う組み合わせなので、ともにStringを用いています。このようにしてインスタンスを生成すると、配列変数のようにしてデータを設定・取得することが可能です。

Dictionaryクラスのデータの設定
(変数名) [キー]=値;

16行目から21行目でこの処理が行われ、国名がキーとなり、首都を値として、関係性が設定されます。(図6-2.)

図6-2.Dictionaryクラスの働き
Dictionaryクラスの働き

配列変数やListが、[]内にインデックスを入れて値を代入・取得しているのに対し、Dictionaryは、[]にキーを入れます。

データの出力

ハッシュテーブルは、配列とは違い、インデックスに順序や前後関係があるわけではありませんそこで、配列を用いてすべての内容を出力しようとした場合、まずはキーをすべて出力する必要があります。その処理が行われているのが、21行目です。

Dictionaryクラスのキーの取得
(変数名).Keys

これにより、Dictionaryクラスに与えられたキーの一覧が配列として得られます。このサンプルでは、それを利用し、すべてのキーを取得し、それに対応する値を得て、出力しているのです。

HashSet

サンプルプログラム

最後に、データを重複なく管理する方法について説明します。そのために利用するクラスが、HashSetクラスです。まずは、以下のサンプルを実行してみてください。

プロジェクトSampleEx604/Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleEx604
{
    class Program
    {
        static void Main(string[] args)
        {
            //  ハッシュセットの生成
            HashSet t = new HashSet();
            //  データの追加
            t.Add(1);
            t.Add(2);
            t.Add(3);
            t.Add(1);
            //  データの出力
            foreach (int i in t)
            {
                Console.WriteLine("{0}", i);
            }
        }
    }
}
実行結果
1
2
3

HashSetの使用方法は、Arrayに似ています。このサンプルでは、14行目で、intのデータが入るハッシュセットを生成し、15行目から18行目のAdd()メソッドを用いてデータを追加しています。追加しているデータは、1,2,3,1なので、Arrayであれば、この順序にデータが格納されるはずです。

しかし、foreachを用いて出力したデータの結果は、1,2,3となっています。1は重複しているため、複数登録できないためです。このように、HashSetクラスは、重複なくデータを登録できます。(図6-3.)

図6-3.HashSetクラスの働き
HashSetクラスの働き

Collectionクラスは、このほかにもいくつも存在します。しかし、以上のクラスを押さえておけば、たいていのことができます。まずは、これらのクラスを上手に利用することから始めましょう。

練習問題 : 問題6.