Visual Basic 初級講座 [改訂版]
VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

第15回 配列

2020/6/28

この記事が対象とする製品・バージョン

VB2019 Visual Basic 2019 対象です。
VB2017 Visual Basic 2017 対象です。
VB2015 Visual Basic 2015 対象です。
VB2013 Visual Basic 2013 対象です。
VB2012 Visual Basic 2012 対象です。
VB2010 Visual Basic 2010 対象です。
VB2008 Visual Basic 2008 対象です。
VB2005 Visual Basic 2005 対象です。
VB.NET 2003 Visual Basic.NET 2003 対象外ですがほとんどの説明があてはまるので参考になります。
VB.NET 2002 Visual Basic.NET (2002) 対象外ですがほとんどの説明があてはまるので参考になります。
VB6対応 Visual Basic 6.0 × 対象外です。

 

目次

 

 

1.配列の概要

配列(はいれつ)とは似たような変数をまとめて簡単に取り扱うための技術です。

似たような技術に「コレクション」(リストやディクショナリー)というものがあり、コレクションの方が高度な機能を簡単に扱いやすくなっていますので、配列よりもコレクションを使用することをお勧めします。コレクションについては次回説明します。

しかし、配列の方が昔からある技術でより基本的です。高度な機能を扱うには面倒な処理が必要な場合もありますが、それは配列自体がシンプルだからです。フレームワークが提供するメソッドの引数や戻り値には配列を利用するものも多々あります。ですから、まず基本の配列を理解したうえで、もっと扱いやすコレクションを理解するという順番が良いと思います。

 

さて、次のように3つの数値型の変数を使うプログラムを考えて見ましょう。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim number1 As Integer
Dim number2 As Integer
Dim number3 As Integer

number1 = 101
number2 = 25
number3 = 3

Debug.WriteLine(number1 + number2 + number3)

Debug.WriteLineが表示される場所

 

配列を使うと このプログラムにでてくる3つの変数をまとめて次のように記述することができます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim number(2) As Integer
number(0) = 101
number(1) = 25
number(2) = 3

Debug.WriteLine(number(0) + number(1) + number(2))

見るとわかるように配列にすると変数の後ろにかっこがついたような書き方になります。

 

配列は普通の変数と同じように使用できます。使用するときにはかっこの中に番号を指定するのが、普通の変数との違いです。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

'普通の変数の読み書き
Dim nation As String
nation = "カンボジア"
Debug.WriteLine(nation)

'配列の読み書き
Dim nations(0) As String
nations(0) = "カンボジア"
Debug.WriteLine(nations(0))

かっこの中の番号のことを添字(そえじ)またはインデックスなどと呼びます。

配列の下限は常に 0 です。

配列の上限はDimなどで宣言するときに指定します。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019


Dim
number(2) As Integer

■リスト4:配列の宣言

この例のように (2) と宣言すると、0~2までの3つの要素を持つ配列を宣言したことになります。つまり、0, 1, 2と3つの変数が一度に宣言されたような効果があるわけです。この例の配列の場合、「配列のサイズは3である」のように「サイズ」という言葉を使うこともあります。「配列のサイズ」と言われたら通常はその配列の要素の数を表しています。

配列用語

 

要素が3つくらいの配列なら別々に3つの変数を宣言してもさして手間はかかりませんが、要素が100個くらいになると配列のメリットがよくわかります。宣言するのが大変だという理由だけで配列を作成するケースはそれほど多くありませんが皆無ではありません。

メモ メモ  -  配列の下限の明示

2020年現在では使われることはまずないと思いますが、添字の下限が 0 であることを宣言で明示することもできます。次のように記述します。

VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019


Dim
number(0 To 2) As Integer

配列の下限は 0 固定であり、 1 To 2 などと書くことはできません。

昔(1998年ごろ)のVB6時代までは配列の下限が 0 に固定されていなかったため、宣言時に下限を指定する構文に意味がありました。この書き方に慣れたプログラマーがスムーズに.NETを使えるように構文だけ導入されたものです。

 

 

2.配列 の書き方

2-1.構文

配列の構文をまとめると次の通りです。

これは一例なのでDim以外のキーワードで宣言したり、Debug.WriteLine以外の機能で値を取得することももちろんできます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

'配列の宣言
Dim 変数名(添字の最大値) As 型名

'配列の要素への値の代入
変数名(添字) = 値

'配列の要素からの値の取得
Debug.WriteLine(変数名(添字))

 

実例はさきほど紹介していますが、並べて書くとわかりやすいと思うので、同じようなものをもう1度掲載します。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

'配列の宣言 numbers(0) ~ numbers(2) までが使用できるようになります。
Dim numbers(2) As Integer

'配列の要素への値の代入
numbers(0) = 627

'配列の要素からの値の取得
Debug..WriteLine(numbers(0))

 

2-2.配列の初期化

次のようにして配列に初期値を設定することができます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim nations() As String = {"カンボジア", "ミャンマー", "ラオス", "ブルネイ", "パラオ"}

Dim numbers() As Integer = {101, 25, 3}

初期値を設定する場合は ( ) の中は空にします。

この例の場合、nationsは要素が5個あるString型の配列、numbersは要素が3個あるInteger型の配列になります。

VB2008以上であれば、型推論が使用できるので、 As String、As Integer を省略しても同じ意味になります。

VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim nations() = {"カンボジア", "ミャンマー", "ラオス", "ブルネイ", "パラオ"}

Dim numbers() = {101, 25, 3}

型推論を使うと ( ) も省略できて、次のように書いても有効です。

VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim nations = {"カンボジア", "ミャンマー", "ラオス", "ブルネイ", "パラオ"}

Dim numbers = {101, 25, 3}

ただ、 ( ) まで省略してしまうと配列であることがわかりにくくなってしまうので、私は ( ) は付けるほうが良いのではないかと思います。

 

2-3.配列リテラル

{ } で囲む記述方法は配列のリテラルを生成するので、宣言以外の場所で配列として使用することもできます。

" " で囲む文字列リテラルが String型の変数が必要な場所で使用できるのと同じです。

たとえば、File.AppendAllLinesメソッド(読み方:AppendAllLines = アペンドオールラインズ)は、テキストファイルに何行か書き込むメソッドです。書き込む内容は 配列 などで指定する必要があります。

次の例ではこれを利用して C:\temp\test.txt に カンボジア、ミャンマー、ラオス、ブルネイ、パラオの5行を追記します。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim lines() As String = {"カンボジア", "ミャンマー", "ラオス", "ブルネイ", "パラオ"}

IO.File.AppendAllLines("C:\temp\test.txt", lines)

これを変数 lines を使わずに直接次のよう書くこともできます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019


IO.File.AppendAllLines("C:\temp\test.txt", {"カンボジア", "ミャンマー", "ラオス", "ブルネイ", "パラオ"})

 

配列リテラルでは要素に変数を使用することもできます。

たとえば、このAppendAllLinesメソッドでたった1行だけ変数の値を追記したい場合、次のように記述できます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim message As String = "この1行を追記したい。"

IO.File.AppendAllLines("C:\temp\test.txt", {message})

AppendAllLinesメソッドの第2引数で message が { } で囲まれて {message} となっているところがポイントです。 { } を付けることで、要素が1個だけの配列になるわけです。

もし、 { } をとると、第2引数には単なる String型の変数を指定していることになります。 AppendAllLinesメソッドは単一のStringを引数にとるように定義されていませんので、その場合はエラーになります。

 

2-4.Visual Studioの支援機能

Visual Studioでデバッグ実行すると配列の内容を簡単に確認することができます。

ブレークポイントを付けた状態で実行し、実行が停止している状態で、配列を表す変数の上にマウスをホバーさせるとそれだけで配列の内容を確認することができます。

→ブレークポイントについては、第10回を参照してください。

デバッグ実行で配列の中身を確認する

変数を右クリックして、クイックウォッチを選択して中身を確認することもできます。

 

3.配列の使用例

3-1.ループとの組み合わせ

配列は For ~ Nextのループととても相性がよいです。

VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim nations(4) As String

nations(0) = "カンボジア"
nations(1) = "ミャンマー"
nations(2) = "ラオス"
nations(3) = "ブルネイ"
nations(4) = "パラオ"

For i As Integer = 0 To nations.Length - 1
    Debug.WriteLine(nations(i))
Next

Debug.WriteLineが表示される場所

このように記述すると配列のカウンター変数 i が 0, 1, 2・・・と増えていくのにしたがって、配列 nations(i) もそれに応じて nations(0)、nations(1)、nations(2)、・・・となっていくので、配列のすべての内容に簡単にアクセスすることができます。

配列のサイズは Length プロパティ (読み方:Length = レンクス)で取得できます。VB2008以上ではLengthの代わりに Count (読み方:Count = カウント)を使うこともできます。

ひとつ重要な注意としては、配列のサイズと添字の最大値は必ず 1 ずれているという点です。この例の配列 nationsのサイズは 5 ですが、添字の最大値は 4 です。そのため、For ~ Next 文で To に指定するのは、nations.Length - 1 のように サイズを - 1した値である必要があります。

ここを To nations.Length と記述してしまうと、最後の周で nations(5) へのアクセスが発生します。nationsは 4 までなので 5 にアクセスするとエラー(IndexOutOfRangeException)が発生します。

メモ メモ  -  UBoundで添字の最大値を取得

配列の添字の最大値は必ず nations.Length - 1 または nations.Count - 1 のようにサイズ - 1 になります。VB用の伝統的なUBound関数(読み方:UBound = ユーバウンド)を使うと -1 しなくても添字の最大値を取得できます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim nations(4) As String

'どれも 4 になります。
Dim maxIndex1 As Integer = nations.Length - 1
Dim maxIndex2 As Integer = nations.Count - 1 'VB2008以降
Dim maxIndex3 As Integer = UBound(nations) 

-1 する場合としない場合が紛らわしくなってくるので統一して使用することをお勧めしますが、UBoundがVB用の関数であることを考えるとC#やJavaなど他の言語でも通用する -1 すると言うほうに統一したほうがわかりやすいのではないかと思います。

参考:Visual Basic サンプル集 配列の要素の数を取得する

 

3-2.AddRange

WindowsフォームのListBoxやComboBoxコントロールのように複数の値を受け入れるが前提になっているクラスには、 AddRangeメソッド(読み方:AddRange = アドレンジ)というメソッドが用意されていることがあります。これを使うと値を1つずつ追加していくのではなく、配列やコレクションを使用して一括で値を登録することができます。

ListBoxのAddRangeメソッドで配列を一括追加

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019


ListBox1.Items.AddRange({"カンボジア", "ミャンマー", "ラオス", "ブルネイ", "パラオ"})

次のように配列リテラルを使わないでももちろんOKですが、これだと値を1つずつ追加して方式と大差なく、便利さは感じません。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim nations(4) As String

nations(0) = "カンボジア"
nations(1) = "ミャンマー"
nations(2) = "ラオス"
nations(3) = "ブルネイ"
nations(4) = "パラオ"

ListBox1.Items.AddRange(nations)

 

3-3.動的なサイズの変更

ReDimを使うと配列のサイズを後で変更することができます。

後にならないと要素の数が決定できない場合や、要素が追加・削除される機能などの場合に使用します。(ただ、このような機能はコレクションの方が得意なので、何か事情があるのでなければ配列でやらないほうが楽です。)

このように後でサイズが変更される配列を動的配列とよびます。

宣言の時点でサイズが不明な場合、次のようにカッコの中を空にします。カッコが空の配列はサイズが未決定であることを意味します。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019


Dim
names() As String

宣言時点で仮のサイズを決めたい場合は、通常の配列と同じようにカッコの中に数字を入れても構いません。

 

サイズが未決定なまま配列の要素にアクセスするとエラーになります。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019


Dim
names() As String
names(0) = "後醍醐天皇" '←ここでNullReferenceExceptionが発生します。

 

サイズを決定・変更するにはReDimステートメント(読み方:ReDim = リディム)を使用します。次の例はサイズを3に設定してから要素にアクセスするのでエラーになりません。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim names() As String

ReDim names(2)

names(0) = "後醍醐天皇"

 

単純に ReDim を使用するとその時点で配列に入っていた内容はすべてクリアされます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim names() As String

ReDim names(2)
names(0) = "後醍醐天皇"
Debug.WriteLine(names(0)) '後醍醐天皇 と出力されます。

ReDim names(3)
Debug.WriteLine(names(0)) '空の行が出力されます。

 

Preserve (読み方:Preserve = プレサーブ)をReDimと一緒に使うと内容はクリアされません。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim names() As String

ReDim names(2)
names(0) = "後醍醐天皇"
Debug.WriteLine(names(0)) '後醍醐天皇 と出力されます。

ReDim Preserve names(3)
Debug.WriteLine(names(0)) '後醍醐天皇 と出力されます。

後醍醐天皇は鎌倉時代末期から南北朝時代の天皇で、武家政権を打破し一時的に天皇親政を復活させました。これが建武の新政です。歴代天皇の中では雄略天皇に並んで非常に活動的だった天皇です。

Preserveはこのように便利に使用できますが、ループの中などで繰り返し使用すると体感できるほど処理が遅いです。

Preserveを指定してもしなくてもReDimを使うと、内部では新しい配列が作成されます。Preserveを指定した場合、その新しい配列に古い配列に入っていた値がすべてコピーされます。つまり、ReDim Preserveを使うたびに内部では配列のすべての要素のコピーが実行されるので大きな配列で繰り返し使用すると遅くなるというわけです。もっとも、最初に書いたように、ReDimが必要な場合は、配列よりもコレクションを使うべきで、コレクションであれば簡単に要素の数を変更できるので、このようなことに悩まずにすみます。

 

4.For Each ~ Next

配列やコレクションなどには For Each ~ Next (読み方:Each = イーチ)という繰り返しの構文が用意されており、要素を1つずつ取り出して処理することができます。

次の例は配列の全内容を出力ウィンドウの出力元デバッグに出力します。

VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim nations(4) As String

nations(0) = "カンボジア"
nations(1) = "ミャンマー"
nations(2) = "ラオス"
nations(3) = "ブルネイ"
nations(4) = "パラオ"

For Each nation As String In nations
    Debug.WriteLine(nation)
Next

Debug.WriteLineが表示される場所

これは先ほど出てきたFor ~ Nextでのループに似ており、実現されることも同じです。

しかし、通常のFor ~ Nextの場合は、ループの回数を To nations.Length - 1 と指定する必要があったのに、For Each ~ Nextの構文ではループの回数を指定する必要がなく簡単に書けます。

ループの回数を指定する必要がないのは、配列の全要素を対象にループするから、回数を別途指定する意味がないからです。

回数を表すカウンター変数も不要で、その代わりカウンター変数の位置にはループの要素を表す変数を指定します。

 

構文を簡易的に示すと次の通りです。赤い字で書いている部分は必ず記述する必要があります。

VB6 VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

For Each 変数 In 配列など

     繰り返して実行する処理

Next 変数

 

配列をループで処理する場合、全要素を1つずつ処理したい場合が多いので、For ~ Nextよりも For Each ~ Nextの方が使う機会が多いです。

通常のFor ~ Next と同じようにExit For と Continue Forも使用できます。

 

5.配列のコピー

5-1.コピーの方法

配列をコピーするには ToArray メソッド(読み方:ToArray = トゥーアレイ)を使用します。

次のプログラムでは namesB は namesAのコピーになります。

VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim namesA() As String = {"後醍醐天皇", "カイ・ハンセン", "スタンダ-ル"}
Dim namesB() As String = namesA.ToArray

VB2005以前の場合は、少し面倒なのですが、Cloneメソッド(読み方:Clone = クローン)を使って次のようにします。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim namesA() As String = {"後醍醐天皇", "カイ・ハンセン", "スタンダ-ル"}
Dim namesB() As String = CType(namesA.Clone, String())

Cloneの結果は、形式上Object型になるので、CTypeを使って目的の型の配列に変換する必要があります。この場合、Stringの配列であることを示すために String() と記述します。

 

5-2.注意すべきダメな例

注意すべきなのは、次のプログラムは配列のコピーを作っていないという点です。初心者の方はこれで配列のコピーが作られたつもりになってミスをしてしまいます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim namesA() As String = {"後醍醐天皇", "カイ・ハンセン", "スタンダ-ル"}
Dim namesB() As String = namesA '←これでは配列のコピーを作られていません!

これのどこがダメかは次の例で確認できます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim namesA() As String = {"後醍醐天皇", "カイ・ハンセン", "スタンダ-ル"}
Dim namesB() As String = namesA '←これでは配列のコピーを作られていません!

namesA(1) = "ガンジー"

Debug.WriteLine(namesB(1)) 'ガンジーと表示されます。

Debug.WriteLineが表示される場所

namesA(1) の値をガンジーに変更した後で、namesB(1) の値を表示してみると、なんと「ガンジー」と表示されます。

つまり、namesA と namesB は連動しているのです。というよりも同じ実体を別の変数から見る状態になっているのです。

プログラムによってはこの状態の方が好ましい場合もあるので、このようなことをしてはいけないという意味ではありません。意図的にこうしたいのであれば問題ありません。

 

一方、ToArrayを使った例では、namesA(1) を変更しても、その前にコピーした値が保持されるので、namesB(1)はカイ・ハンセンのままです。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim namesA() As String = {"後醍醐天皇", "カイ・ハンセン", "スタンダ-ル"}
Dim namesB() As String = namesA.ToArray

namesA(1) = "ガンジー"

Debug.WriteLine(namesB(1)) 'カイ・ハンセンと表示されます。

 

5-3.内部の動作

いったい何が起こっているのでしょうか?

 

Dim namesA() As String = {"後醍醐天皇", "カイ・ハンセン", "スタンダ-ル"}

という命令は"後醍醐天皇", "カイ・ハンセン"、"スタンダール"からなる配列のインスタンスを 変数namesA から参照できるという意味になります。

配列の実体と変数

 

namesB = namesA という命令は、namesAが見ているインスタンスをnamesBも見るという意味になり、次の状態を作り出します。

同じ配列の参照を別の変数で共有する

 

この状態で namesA(1) = "ガンジー" という代入を実行すると次のようになります。

別の変数でも変更が連動する

 

なので、namesA を変更すると、namesBからも同じ変更が見えるのです。

 

一方、ToArrayメソッドやCloneメソッドは配列のインスタンスをコピーしてもう1つ別のインスタンスを作り出します。

namesB = namesA.ToArray という命令で namesAの配列のインスタンスをコピーしたインスタンスを namesB が指すようなるというわけです。

配列のコピー

 

ですから、namesAの状態を変更してもnamesBにはもはや関係がないということになります。

配列のコピー

 

 

6.2次元配列

6-1.配列の次元

複数の添字を持つ配列を作ることができます。添字の数を配列の「次元」(じげん)と呼びます。

これまで説明した配列は Dim names(2) のように添字を1つしか使っていないので1次元配列です。

 

表のようなイメージで配列を使いたい場合は、添字を2つにした2次元配列を使用します。

 

6-2.2次元配列の実例

次の表は2005年時点で人口の多い都市圏ベスト5を各年代で人口の順に並べたものです。

  1950年 1960年 1970年 1980年 1990年 2000年 2005年
  1 2 3 4 5 6 7
1 ニューヨーク ニューヨーク ニューヨーク 東京 東京 東京 東京
2 東京 東京 東京 ニューヨーク ニューヨーク ニューヨーク ニューヨーク
3 エッセン エッセン 大阪 メキシコシティ ソウル ソウル ソウル
4 大阪 大阪 エッセン 大阪 メキシコシティ メキシコシティ メキシコシティ
5 パリ パリ メキシコシティ サンパウロ 大阪 ジャカルタ ジャカルタ

参考:Wikipedia

このようなデータをプログラムで扱いたい場合、二次元配列はおそらく良い選択肢でない場合がほとんどでしょう。

このようなデータを扱うプログラムはデータベースと連携することが多く、データベース関連の機能を利用することが多いはずです。

しかし、今回は勉強のためこれを二次元配列で扱ってみましょう。

まず、年代が7個あるので、1つ目の添字の最大値は6です。それから、1位から5位まで並べてみるので、2つ目の添字の最大値は4です。

添字はカンマで区切って表現します。

この配列の宣言は次のようになります。

VB6 VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019


Dim
cities(6, 4) As String

cities(0, 0)は1つ目の年代(1950年)の第1位を表すので「ニューヨーク」です。

cities(2, 3) は3つ目の年代の第4位を表すので、1970年に4位だった「エッセン」という意味になります。

この配列に上記のデータを代入するのはなかなか骨が折れます。たとえば、次のようなプログラムになります。

VB6 VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim cities(6, 4) As String

cities(0, 0) = "ニューヨーク"
cities(0, 1) = "東京"
cities(0, 2) = "エッセン"
'・・・中略
cities(6, 3) = "メキシコシティ"
cities(6, 4) = "ジャカルタ"

リテラルを使うと少しは楽になるでしょうか?/p>

リテラルを使う場合は次のようになります。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim cities(,) = {
    {"ニューヨーク", "東京", "エッセン", "大阪", "パリ"},
    {"ニューヨーク", "東京", "エッセン", "大阪", "パリ"},
    {"ニューヨーク", "東京", "大阪", "エッセン", "メキシコシティ"},
    {"東京", "ニューヨーク", "メキシコシティ", "大阪", "サンパウロ"},
    {"東京", "ニューヨーク", "ソウル", "メキシコシティ", "大阪"},
    {"東京", "ニューヨーク", "ソウル", "メキシコシティ", "ジャカルタ"},
    {"東京", "ニューヨーク", "ソウル", "メキシコシティ", "ジャカルタ"}
}

配列リテラルで初期化しているので、宣言時には添字を記述しません。そうすると奇妙ですがこの例のようにカンマだけが残り (,) という記述になります。

リテラルの方は二次元配列なので { } のなかに { } があります。

また、リテラルが長いので途中で改行しました。記号なしで改行できるのはVB2010以降からなので、VB2008で実行する場合は、 行末に改行記号 _ を付けてください。

 

データを投入する準備が大変でしたが、後は数値でアクセスできます。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim cities(,) = {
    {"ニューヨーク", "東京", "エッセン", "大阪", "パリ"},
    {"ニューヨーク", "東京", "エッセン", "大阪", "パリ"},
    {"ニューヨーク", "東京", "大阪", "エッセン", "メキシコシティ"},
    {"東京", "ニューヨーク", "メキシコシティ", "大阪", "サンパウロ"},
    {"東京", "ニューヨーク", "ソウル", "メキシコシティ", "大阪"},
    {"東京", "ニューヨーク", "ソウル", "メキシコシティ", "ジャカルタ"},
    {"東京", "ニューヨーク", "ソウル", "メキシコシティ", "ジャカルタ"}
}

Debug.WriteLine(cities(0, 0)) 'ニューヨーク
Debug.WriteLine(cities(2, 3)) 'エッセン
Debug.WriteLine(cities(6, 4)) 'ジャカルタ

Debug.WriteLineが表示される場所

 

7.その他の配列の機能

7-1.Arrayクラス

配列はフレームワークの Array クラスです(読み方:Array = アレイ)。Arrayクラスの持つメソッドやプロパティを使用できます。

配列をコピーするところで説明したCloneメソッドもArrayクラスのメソッドです。(ToArrayメソッドは初級講座ではまだ説明していない「拡張メソッド」という種類のメソッドで、一見Arrayクラスのメソッドのように振舞っていますが、実はEnumerableクラスのメソッドです。拡張メソッドはこのように別のクラスで定義しているのにそのクラスのメソッドであるかのように見せる技術です。)

Arrayクラスの主なメンバを表にまとめておきます。この他にもメソッドやプロパティは存在しますので興味のある方はMicrosoft Docsで調べてみてください。

メンバー 読み方 説明
Length レンクス 配列の要素の数を表します。
Rank ランク 配列の次元の数を表します。
GetLength ゲットレンクス 特定の次元の要素の数を返します。
IndexOf インデックスオブ 前方から要素を検索します。
LastIndexOf ラストインデックスオブ 後方から要素を検索します。
Sort ソート 要素を並び替えます。

 

7-2.配列の検索

IndexOfメソッド、LastIndexOfメソッドは配列の要素を検索して最初に見つかった要素のインデックスを返します。IndexOfは前方から検索を開始し、LastIndexOfは後方から検索を開始します。値が見つからない場合はどちらも -1 を返します。以下の例は単純に検索する例ですが、検索開始位置などを指定することもできます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim states(5) As String
states(0) = "カリフォルニア"
states(1) = "テキサス"
states(2) = "ニューヨーク"
states(3) = "ニューヨーク"
states(4) = "カリフォルニア"
states(5) = "ミシシッピ

Dim index As Integer
index = Array.IndexOf(states, "ニューヨーク") '2を返します。

Dim lastIndex As Integer
lastIndex = Array.LastIndexOf(states, "カリフォルニア") '4を返します。

Dim noneIndex As Integer
noneIndex = Array.LastIndexOf(states, "兵庫") '-1を返します。

この例を見るとわかるようにIndexOfやLastIndexOfは共有メソッドです。states.IndexOf と書くのではなく、Array.IndexOf と書きます。

私はこれらは非共有メソッドにして、index = states.IndexOf("ニューヨーク")のように書けた方がスマートだと思うのですが、残念ながらこれを最初に設計したマイクロソフトの技術者はそうは思わなかったようです。

 

7-3.配列を結合して1つの文字列にする

String.Joinメソッド(読み方:Join = ジョイン)を使用すると、配列のすべての要素を結合して1つの文字列にすることができます。

結合するときに要素の間に文字を挿入することができます。次の例では , を挿入して結合します。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim names() As String = {"イノシシ", "ウマ", "アメンボ", "オットセイ", "エビ"}

Dim line As String = String.Join(",", names)

Debug.WriteLine(line) 'イノシシ,ウマ,アメンボ,オットセイ,エビ と表示されます。

Debug.WriteLineが表示される場所

 

何も挿入しないで結合することもできます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim names() As String = {"イノシシ", "ウマ", "アメンボ", "オットセイ", "エビ"}

Dim line As String = String.Join("", names)

Debug.WriteLine(line) 'イノシシウマアメンボオットセイエビ と表示されます。

 

改行を挿入することもできます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim names() As String = {"イノシシ", "ウマ", "アメンボ", "オットセイ", "エビ"}

Dim line As String = String.Join(Environment.NewLine, names)

Debug.WriteLine(line) '5行で出力されます。

 

7-4.配列の並び替え

Sortメソッドを使用すると配列の内容を辞書順に並び替えます。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim names() As String = {"イノシシ", "ウマ", "アメンボ", "オットセイ", "エビ"}

Array.Sort(names)

Dim line As String = String.Join(",", names)
Debug.WriteLine(line) 'アメンボ,イノシシ,ウマ,エビ,オットセイ と表示されます。

 

このSortメソッドには2つの配列を連動して並び替える使い方があります。

次の例をご覧下さい。

VB.NET 2002 VB.NET 2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

'国名と対応する首都名の配列を作成します。
Dim nations() As String = {"日本", "アメリカ", "韓国", "イギリス"} '国名
Dim cities() As String = {"東京", "ワシントン", "ソウル", "ロンドン"} '首都名

'国名を並び替えます。(連動して首都名も並び変わります。)
Array.Sort(nations, cities)

'結果を表示します。
For i As Integer = 0 To nations.Length - 1
    Debug.WriteLine(nations(i) & " の首都は " & cities(i))
Next

実行するとちゃんと国名と首都名が正しく表示されます。もちろん国名は辞書順に並び変わります。

この例は2つの配列の位置関係が重要なので、片方の配列だけ並び替えるとおかしくなってしまいます。かといってばらばらに並び替えると、それぞれが辞書順に並ぶのでやはり位置関係がおかしくなってしまいます。

Sortメソッドを使うとこのような場合に、1つの配列の並び替えに連動して、同じ並び替えをもう1つの配列に適用することができます。