たくのろじぃのメモ部屋

プログラミング(C#)の基礎やそれを応用した技術情報をメモしておくブログです。

【C#】WPFアプリケーション入門 #11 連想配列

はじめに

連想配列は配列の要素ひとつひとつに名前を付けるようなイメージです。配列のときはただ要素数を用意しただけなので、要素を呼び出すためには 変数名[値] を指定する必要があります。が、この値が問題で、何番目の要素に欲しいデータが入っているかが分かりません。これを解決するのが連想配列です。

お品書き

今回扱う内容です。

  1. 配列の復習
  2. 連想配列
  3. 実装

1. 配列の復習

配列とは、同じ型やグループに属する値をまとめて管理できるものでした。例えば、年齢データを保管したいとき、

int age_1 = 14;
int age_2 = 20;
int age_3 = 55;
// 以下に続く

このような宣言では無駄にメモリを消費するだけでなく、いちいち変数名を宣言するのが面倒です。こんな時こそ連想配列を使ってスマートにデータを管理します。

int[] age = new int[16]
age[0] = 17;
age[1] = 20;
age[2] = 55;
// 以下に続く

このようにすれば、int 型で確保する変数は1つしかないですが、変数を細分化して使い分けることができます。
しかし、この中から14を取り出すときには age[0] を呼び出す必要があります。事前に age[0] が14という値を保持していることを知っていれば問題ありませんが、知らない場合はプログラムを読まないといけません。

2. 連想配列

連想配列は配列要素にそれぞれ名前とデータを持たせることができます。名前のことを Key といい、値のことを Value といいます。

var 変数名 = new  Dictionary<Key の型, Value の型>();

ここで、var は型推論といい、実行時に型が自動で選ばれます。便利といえば便利ですが、プログラムを読まないとどんなデータを扱うのかが分かりにくいです。逆にどんな型を扱えばいいかが分からないときは迷わず使います。

Dictionary は連想配列を使うためのクラスです。なので、上記の宣言はインスタンス化していることになります。インスタンス化したものはオブジェクトとして扱えるので、Dictionaryに関する操作 (メソッド) もあります。

2.1 要素の追加

連想配列を宣言して要素を追加するときは Add メソッドを使います。

// Key は文字列型、 Value は整数型で管理
var array = new Dictionary<string, int>();

// 要素を追加する
array.Add("高校生", 17);
array.Add("大学生", 20);
array.Add("社会人", 55);

これで配列に要素が追加されます。"高校生"要素には17、"大学生"要素には20、"社会人"要素には55が保持されます。

2.2 要素の表示

表示したいときは、Key を要素で指定するだけです。

MessageBox.Show(array["大学生"].ToString());

これで ["大学生"] という Key から 20 という値を取り出せます。注意が必要なのは、Value の型です。この例では int 型になっているので、メッセージを表示するには文字列型に変換する必要があります。

保持された要素すべてを取り出すときは、foreach 文 を使うと良いです。foreach は for 文とよく似ていますが、要素数 (保持する情報の数) を取得できるのがメリットです。in (パラメータ演算子) は要素を持つ変数から、その要素数を得ることができます。

foreach(型 変数またはオブジェクト in 要素をもつ変数) {
    //処理
}

これを使って要素を取り出してみます。まずは型ですが、保持しているのは整数型なので、int です。次に任意の変数 (Value) を用意します。そして、要素を持つ変数は上記の例から array です。これらを組み合わせればいいわけです。

foreach (int Value in array.Values)
{
    MessageBox.Show(Value);
}

これで保存された Value が表示されます。Key に関しても同様にして呼び出せます。ただし、in array.Keys と変更する必要があります。

3. 実装

連想配列を使ったプログラムを書いてみます。 XAMLコードは次の通りです。

<Window x:Class="_006_連想配列.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:_006_連想配列"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="300">
    <Grid>
        <Label Content="配列[0]" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
        <Label Content="配列[1]" HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top"/>
        <Label Content="配列[2]" HorizontalAlignment="Left" Margin="10,72,0,0" VerticalAlignment="Top"/>
        <Label Content="配列[3]" HorizontalAlignment="Left" Margin="10,103,0,0" VerticalAlignment="Top"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="58,14,0,0" TextWrapping="Wrap" Text="なにか" VerticalAlignment="Top" Width="120" x:Name="Textbox0"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="58,44,0,0" TextWrapping="Wrap" Text="文字を" VerticalAlignment="Top" Width="120" x:Name="Textbox1"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="58,75,0,0" TextWrapping="Wrap" Text="入力" VerticalAlignment="Top" Width="120" x:Name="Textbox2"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="58,107,0,0" TextWrapping="Wrap" Text="してみて" VerticalAlignment="Top" Width="120" x:Name="Textbox3"/>
        <Button Content="書き換える" HorizontalAlignment="Left" Margin="58,139,0,0" VerticalAlignment="Top" Width="90" Click="Button_Write" />
        <Label Content="配列名" HorizontalAlignment="Left" Margin="197,10,0,0" VerticalAlignment="Top" x:Name="Label_array0" Height="27"/>
        <Label Content="配列名" HorizontalAlignment="Left" Margin="197,41,0,0" VerticalAlignment="Top" Height="26" x:Name="Label_array1"/>
        <Label Content="配列名" HorizontalAlignment="Left" Margin="197,72,0,0" VerticalAlignment="Top" Height="27" x:Name="Label_array2"/>
        <Label Content="配列名" HorizontalAlignment="Left" Margin="197,107,0,0" VerticalAlignment="Top" Height="27" x:Name="Label_array3"/>
        <Button Content="表示" HorizontalAlignment="Left" Margin="161,139,0,0" VerticalAlignment="Top" Width="90" Click="Button_Show"/>

    </Grid>
</Window>

ロジックは次の通りです。

namespace _006_連想配列
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        //連想配列にテキストボックスの情報を書き込む
        static void Array_Write()
        {
            //Textbox は MainWindow に存在するのでインスタンス化する必要がある。
            //インスタンスを取得した上でその中の TextBox を使う
            var mainWindow = (MainWindow)App.Current.MainWindow;

            //連想配列は Dictionary<> を用いる
            //<配列の名前, 配列に入れるデータ>の各型を宣言する
            var array = new Dictionary<string, string>();

            //キーを個別に保管しておくための配列(変換する)
            string[] key = new string[4];

            //値を個別に保管しておくための配列(変換する)
            string[] value = new string[4];

            //foreach を回すための初期値
            int i = 0, j = 0;

            //各要素に配列名とそこに入れるデータを参照する
            array.Add("配列1", mainWindow.Textbox0.ToString());
            array.Add("配列2", mainWindow.Textbox1.ToString());
            array.Add("配列3", mainWindow.Textbox2.ToString());
            array.Add("配列4", mainWindow.Textbox3.ToString());

            //array のキーの数だけ繰り返して、キーを個々に格納
            foreach(string Key in array.Keys)
            {
                key[i] = Key;
                i++;
            }

            //array の値の数だけ繰り返して、値を個々に格納
            foreach (string Value in array.Keys)
            {
                value[j] = Value;
                j++;
            }

            //ウィンドウの配列名のところに設定した配列名が更新される
            mainWindow.Label_array0.Content = key[0];
            mainWindow.Label_array1.Content = key[1];
            mainWindow.Label_array2.Content = key[2];
            mainWindow.Label_array3.Content = key[3];
        }

        private void Button_Write(object sender, RoutedEventArgs e)
        {
            //連想配列へ書き込む
            Array_Write();
            MessageBox.Show("書き込みました");
        }

        private void Button_Show(object sender, RoutedEventArgs e)
        { 
            MessageBox.Show("配列名 " + Label_array0.Content + " には " + Textbox0.Text + " が代入されています。");
            MessageBox.Show("配列名 " + Label_array1.Content + " には " + Textbox1.Text + " が代入されています。");
            MessageBox.Show("配列名 " + Label_array2.Content + " には " + Textbox2.Text + " が代入されています。");
            MessageBox.Show("配列名 " + Label_array3.Content + " には " + Textbox3.Text + " が代入されています。");
        }
    }
}

これを実行すると、こんな感じになります。

f:id:takunology:20190711031621p:plain

製作したソースコードはこちらにあります。

github.com

おわりに

連想配列を使うと値をキーで管理できます。アプリ開発では配列だけで管理すると、どこに何のデータが管理されているかが分からず、不便なことがあるかもしれません。また、Dictionary を使うことによって必要な要素数を初期化しておく必要がありません。つまり、データが増えることによって要素数が拡張されます。これはこれで便利ですが、ただの配列よりもメモリを消費するので注意が必要です。