忍者ブログ

VB.NET-TIPS などプログラミングについて

VB.NETのTIPS(小技集)を中心に、Javascript、PHP その他のプログラミングについて少し役に立つ情報を発信します。いわゆる個人的な忘備録ですが、みなさんのお役に立てれば幸いです。

配列の使い方について(Dim, Redim)

配列は似た性質のデータをまとめて取り扱えるようにするデータ形式です。 配列の機能は、その昔の言語である FORTRAN , C言語 (私も使った言語ですが)等でも持っています。 ここまで配列の機能が残っているということは、それなりに使い勝手が良いのではないかと思います。 そこで今回は、配列の使い方について順を追って説明したいと思います。


■簡単な配列の宣言と使い方

以下のソースを見て下さい。 処理の前半は、配列を利用しない場合の合計処理を示しています。 配列が無い場合は、値を別々の変数に宣言して、それぞれを参照し合計を求めています。 配列を利用しないと非常に煩雑になってしまします。

処理の後半で配列を利用する場合を示しています。 配列の各要素に値を設定する部分は、ベタに記述していますが、合計を求めるところで 配列の処理らしさが現れています。 (この処理などは初歩の初歩なので特に難しくないと思います。)

    Private Sub btnArray_Click(sender As Object, e As EventArgs) Handles btnArray.Click
        '===配列を利用しない場合の合計処理===
        '各変数の宣言
        Dim nVal1 As Integer
        Dim nVal2 As Integer
        Dim nVal3 As Integer
        Dim nVal4 As Integer
        Dim nVal5 As Integer
        '値の設定
        nVal1 = 1
        nVal2 = 10
        nVal3 = 100
        nVal4 = 1000
        nVal5 = 10000
        '値の合計
        Dim nSum As Integer
        nSum = nVal1 + nVal2 + nVal3 + nVal4 + nVal5
        Console.WriteLine("配列を利用しない場合の合計処理:{0}", nSum)

        '===配列を利用===
        '配列宣言
        Dim arr(5) As Integer
        '要素に値設定
        arr(1) = 1
        arr(2) = 10
        arr(3) = 100
        arr(4) = 1000
        arr(5) = 10000
        '指標宣言
        Dim i As Integer
        '合計計算
        nSum = 0
        For i = 1 To 5
            nSum = nSum + arr(i)
        Next
        Console.WriteLine("配列を利用した場合の合計処理:{0}", nSum)
    End Sub

実行結果がコンソールには以下様に表示されます。(当然合計値は同じ結果)

配列を利用しない場合の合計処理:11111
配列を利用した場合の合計処理:11111


■配列宣言の落とし穴

上記のソースでは配列宣言で Dim arr(5) As Integer と宣言しましたが、 領域としては指標が「1」~「5」まで確保されたかの様に感じますが、実は指標「0」の要素が存在します。
そこで上記のソースを以下の様に変更し実行してみます。

    Private Sub btnArray_Click(sender As Object, e As EventArgs) Handles btnArray.Click
        '===配列を利用===
        '配列宣言
        Dim arr(5) As Integer
        '要素に値設定
        arr(1) = 1
        arr(2) = 10
        arr(3) = 100
        arr(4) = 1000
        arr(5) = 10000
        arr(0) = 10000  '指標「0」の要素
        '指標宣言
        Dim i As Integer
        '合計計算
        nSum = 0
        For i = 0 To 5
            nSum = nSum + arr(i)
        Next
        Console.WriteLine("配列を利用した場合の合計処理:{0}", nSum)
    End Sub
配列を利用した場合の合計処理:21111

結果を見れば指標「0」の要素が存在することが分かります。

Dim arr(5) で5個の領域を宣言したつもりが指標「0」の要素が存在するため、 全体では6個の領域を宣言したことになります。
配列の開始が指標「0」と考えるのか、それとも指標「1」からとするのかで、プログラムの動作や組み方が変わってきます。 複数の人で組む場合にはなおさらで、どちらにするのかを決めておく必要があります。

配列の開始が指標「0」を使うのであれば、必要個数の1個少な目で配列宣言するのか、 それとも指標「1」ならば必要個数で配列宣言し、指標「0」の要素は未使用とするか、と言ったところです。


■配列の初期化

配列の宣言で一緒に初期化ができます。 配列の要素数を記述せずに、宣言のデータ型の後に、=(イコール) で繋ぎ {}(中括弧) で要素を ,(カンマ) で区切って記述します。

上記のソースを配列の初期化を行う様に変更します。

    Private Sub btnArray_Click(sender As Object, e As EventArgs) Handles btnArray.Click
        '配列宣言(初期化)
        Dim arr() As Integer = {10000, 10000, 1000, 100, 10, 1}
        '指標宣言
        Dim i As Integer
        '合計計算
        Dim nSum As Integer
        nSum = 0
        For i = 0 To 5
            nSum = nSum + arr(i)
        Next
        Console.WriteLine("配列宣言(初期化)を利用した場合の合計処理:{0}", nSum)
    End Sub


このソース合計計算の For ループで「5」を直値(リテラル)で記述しています。 この場合は「5」であることが明らかなので問題は無いのですが、 配列の最終の指標が何か分からない時には UBound 等を用います。 以下に項目を新しくして説明します。

■配列の最終指標はUBound

UBound 関数は配列内の指定された次元における最も大きいインデックスを返します。

Public Function UBound(Array As System.Array, Optional Rank As Integer = 1) As Integer
引数:
・Array:任意のデータ型の配列です。 ある次元で最も大きいインデックスを探す対象となる配列です。
・Rank :省略可能です。 Integer. 最も大きいインデックスが返される次元です。
         1番目の次元の場合は「1」、2番目の次元の場合は「2」という形で指定します。
         Rank を省略した場合、「1」が使用されます。
戻り値:Integer型
・指定した次元に設定できるインデックスの最大値です。
・Array に要素が 1 つしかない場合、UBound は 0 を返します。
・Array に要素が存在しない場合 (長さ 0 の文字列の場合など)、UBound は -1 を返します。

以下の例では For ループの最終指標にこの UBound 関数を使っています。

尚、配列のプロパティのには現在の配列の大きさ(長さ)を返してくれる Length がありますのでそれを使っても同様です。 但し、 Length は個数なので「-1」する必要があります。

    Private Sub btnArray_Click(sender As Object, e As EventArgs) Handles btnArray.Click
        '配列宣言(初期化)
        Dim arr() As Integer = {10000, 10000, 1000, 100, 10, 1}
        '指標宣言
        Dim i As Integer
        '合計計算
        Dim nSum As Integer = 0
        '[Ubound]を使った最終指標
        For i = 0 To UBound(arr)
            nSum = nSum + arr(i)
        Next
        Console.WriteLine("配列宣言(初期化)を利用した場合の合計処理:{0}", nSum)

        nSum = 0
        '配列の大きさを返すプロパティ[Length]を使った最終指標
        For i = 0 To arr.Length - 1
            nSum = nSum + arr(i)
        Next
        Console.WriteLine("配列宣言(初期化)を利用した場合の合計処理:{0}", nSum)
    End Sub


■配列のサイズ変更(ReDim)

配列のサイズを変更するために ReDim 命令を使います。
以下のソースでは ReDim 命令で指標が「2」までのサイズに縮めています。 (合計の結果は「21000」を想定していますが...)

    Private Sub btnArray_Click(sender As Object, e As EventArgs) Handles btnArray.Click
        '配列宣言(初期化:要素6個)
        Dim arr() As Integer = {10000, 10000, 1000, 100, 10, 1}
        '配列サイズ変更
        ReDim arr(2)
        '合計計算
        Dim nSum As Integer = 0
        '[Ubound]を使った最終指標
        For i As Integer = 0 To UBound(arr)
            nSum = nSum + arr(i)
        Next
        Console.WriteLine("配列をReDimでサイズ変更した場合の合計処理:{0}", nSum)
    End Sub

しかし結果は「0」となってしまいます。

配列をReDimでサイズ変更した場合の合計処理:0

これは ReDim 命令はサイズを変更した後で全ての要素をその配列のデータ型で初期化してしまうからです。 既に存在した要素を引き継ぐ場合には ReDim 命令で Preserve を指定します。

    Private Sub btnArray_Click(sender As Object, e As EventArgs) Handles btnArray.Click
        '配列宣言(初期化:要素6個)
        Dim arr() As Integer = {10000, 10000, 1000, 100, 10, 1}
        '配列サイズ変更(Preserve指定)
        ReDim Preserve arr(2)
        '合計計算
        Dim nSum As Integer = 0
        '[Ubound]を使った最終指標
        For i As Integer = 0 To UBound(arr)
            nSum = nSum + arr(i)
        Next
        Console.WriteLine("配列をReDimでサイズ変更した場合の合計処理:{0}", nSum)
    End Sub

結果は想定通り「21000」となりました。

配列をReDimでサイズ変更した場合の合計処理:21000



■配列のサイズ未指定での宣言

配列のサイズを指定せずに配列を宣言することができます。 この場合、配列は空の状態で存在し ReDim 命令でサイズを増やしてやらないと使用できません。 (空の状態の状態は Is Nothing で判定できます)
それでは、以下にInteger型配列をサイズ無しで宣言し、配列のサイズを順次拡張して中身が「0」~「9」となる 配列を作成する例を示します。

    Private Sub btnArray_Click(sender As Object, e As EventArgs) Handles btnArray.Click
        '配列宣言
        Dim arr() As Integer    ' = Nothing はあった方がいいと思います
        '「0」~「9」の処理
        For i As Integer = 0 To 9
            If arr Is Nothing Then
                '最初は指標「0」
                ReDim arr(0)
                arr(0) = i
            Else
                '次の指標
                Dim idx As Integer = UBound(arr) + 1
                'サイズ拡張
                ReDim Preserve arr(idx)
                '要素設定
                arr(idx) = i
            End If
        Next
        '配列の要素を文字列として連結
        Dim str As String = ""
        For i As Integer = 0 To UBound(arr)
            If str <> "" Then str &= ","
            str &= arr(i)
        Next
        Console.WriteLine("配列:{0}", str)
    End Sub
配列:0,1,2,3,4,5,6,7,8,9


■配列のループ処理は For Each

上記に配列のループ処理の最終指標として UBound Array.Length を使いましたが、 指標に関係なく配列の要素を順次取得する方法が For Each … Next 処理です。 以下の実際のソースで直感的に分かると思います。
For Each の後ろに配列の要素と同じデータ型の変数を記述し In の後ろに対象となる配列を記述します。
    Private Sub btnArray_Click(sender As Object, e As EventArgs) Handles btnArray.Click
        '配列宣言(初期化)
        Dim arr() As Integer = {10000, 10000, 1000, 100, 10, 1}
        '要素宣言
        Dim nEnt As Integer
        '合計計算
        Dim nSum As Integer = 0
        For Each nEnt In arr
            nSum += nEnt
        Next
        Console.WriteLine("For Each ... Nexを利用した場合の合計処理:{0}", nSum)
    End Sub
For Each ... Nexを利用した場合の合計処理:21111
尚、要素用の変数を別で宣言しなくても以下の様にしても同様な結果となります。
    Private Sub btnArray_Click(sender As Object, e As EventArgs) Handles btnArray.Click
        '配列宣言(初期化)
        Dim arr() As Integer = {10000, 10000, 1000, 100, 10, 1}
        '合計計算
        Dim nSum As Integer = 0
        For Each nEnt As Integer In arr
            nSum += nEnt
        Next
        Console.WriteLine("For Each ... Nexを利用した場合の合計処理:{0}", nSum)
    End Sub

関連する記事

配列の使い方の注意点について(コピー, Clone)
配列の範囲指定によるコピー(Array.Copy, Skip, Take)











PR

コメント

コメントを書く