Visual Basic 中学校 掲示板 投稿内容
タグのない投稿を抽出 統計 RSS

Visual Basic 中学校 > 投稿一覧 >

配列をArrayListに追加する場合の疑問 解決済み

タグの編集...

投稿者 還暦   (社会人)   投稿日時 2022/5/28 11:09:52
いつも勉強させていただいています。今回、標記疑問点について質問させていただきます。
VB2013を使用しています。

以下のプログラムを実行すると、0,1,2,3,4,5と表示された後、555555と表示されます。

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim y As New ArrayList
    Dim z(1) As String
    For i As Integer = 0 To 5
        z(0) = i.ToString
        y.Add(z)
        MsgBox(y(i)(0))
    Next i
    Dim S As String = ""
    For j As Integer = 0 To y.Count - 1
        S &= y(j)(0)
    Next j
    MsgBox(S)
End Sub

Dim z(1) As String をForループの内側にすると、期待通り012345と表示されます。
Forループ内でRedimしても同じです。

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim y As New ArrayList
    For i As Integer = 0 To 5
        Dim z(1) As String
        z(0) = i.ToString
        y.Add(z)
        MsgBox(y(i)(0))
    Next i
    Dim S As String = ""
    For j As Integer = 0 To y.Count - 1
        S &= y(j)(0)
    Next j
    MsgBox(S)
End Sub

なぜこのようになるのか理解できず悩んでいます。
配列ではなく変数だと問題なく012345と表示されます。

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim y As New ArrayList
    Dim z As String
    For i As Integer = 0 To 5
        z = i.ToString
        y.Add(z)
        MsgBox(y(i))
    Next i
    Dim S As String = ""
    For j As Integer = 0 To y.Count - 1
        S &= y(j)
    Next j
    MsgBox(S)
End Sub

配列をArrayListに追加する場合、注意する点についてご教授ください。

投稿者 るきお   (社会人)   投稿日時 2022/5/28 12:37:58
還暦さんの1つ目のサンプルの1つめのForループで何が起こっているかというと、
Dim y As New ArrayList
Dim z(1) As String
For i As Integer = 0 To 5
    z(0) = i.ToString
    y.Add(z)
    MsgBox(y(i)(0))
Next i


配列 z はループの外側で定義されているため、 Form_Load 内で有効なスコープになっています。
つまり、 配列 z の実体は1つしかありません。ここが最大のポイントです。
おそらく還暦さんは、配列 z は、名前こそ z で共通だけれども、y.Add(z) したときにコピーされ、配列は複数の実体を持つことになると誤解されているのではないでしょうか?

y.Add(z) には配列のコピーを作る機能はありません。だから、このループでは、同じ配列の実体をArrayListの各要素に代入していることになります。

たとえば、配列ではありませんが、次のプログラムはどう思われますか?(Option Strict Offが前提ですが、この点はこの問題とは関係ありません。)
Dim y As New ArrayList

Me.Text = "A"
y.Add(Me)
MsgBox(y(0).Text)   'A 
Me.Text = "B"
y.Add(Me)
MsgBox(y(1).Text)   'B 

MsgBox(y(0).Text)   'B 

フォームのTextを "A" 、"B" と変えながら1回ずつ ArrayList に代入していますが、同じフォームを代入しているので、最終的にはどのArrayListの要素からアクセスしても Textプロパティの値は ”B”です。

原理的にはここで説明していることと同じことが起こっているので、よろしければ参考にしてください。
https://www.umayadia.com/VBStandard2/Standard15.htm#A5

なお、y に配列を Addするときに配列本体ではなく、配列のコピーをAddするようにすれば、とりあえずは毎回コピーが作成され実体が分かれるので012345となります。がお勧めではありません。
Dim y As New ArrayList
Dim z(1) As String
For i As Integer = 0 To 5
    z(0) = i.ToString
    y.Add(z.Clone) '←ここでCloneをAddする。 
    MsgBox(y(i)(0))
Next i
Dim S As String = ""
For j As Integer = 0 To y.Count - 1
    S &= y(j)(0)
Next j
MsgBox(S)


還暦さんの2つ目のサンプルはループの中で配列が宣言されているので、毎周配列の実体が作成されます。そのためArryayListの各要素は異なる配列の実体を指すことになります。

ところで、ArrayListは要素の型が指定できないため、使いにくく2005年に陳腐化しました。
2005年に登場した Listクラスは、要素の型が指定できるので便利です。ArrayListを使う代わりにListを使うことをお勧めします。

参考
Dim y As New List(Of String())
For i As Integer = 0 To 5
    '{ } は配列リテラルです。配列作成してyにAddします。 
    y.Add({i.ToString})
    MsgBox(y(i)(0))
Next i

'yの各要素の0番目の要素を結合して1つの文字列にします。 
Dim S = String.Join("", y.Select(Function(item) item(0)))
MsgBox(S)


それから、サンプルにしても還暦さんのプログラムは変数の名前がわかりにくく、この回答を作成するにあたっても、「えっとyはなんだっけ、zが配列で…」のように考えにくかったです。サンプルでももうちょっとわかりやすい名前を付けるとよいと思います。




投稿者 還暦   (社会人)   投稿日時 2022/5/28 13:26:20
るきお様

ご回答ありがとうございました。
ArrayListに追加された配列が同じインスタンスを指していたのですね。納得できました。
Listを使おうと思っていたのですが、配列を要素にする方法が分からずにArryListにしていました。
Listに変更したいと思います。
変数名につきましては、申し訳ありません。気を付けます。

大変勉強になりました。有り難うございました。