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

Visual Basic 中学校 > 投稿一覧 >

二次元配列の要素をカウントしたいです。 解決済み

タグの編集...

投稿者   (学生)   投稿日時 2022/5/12 11:12:08
フォーム上にテキストボックスを表の様に配置しており、以下の様に二次元配列を初期化するメソッドを作成しました。

Table(0,0) = TextBox1_1
Table(0,1) = TextBox2_1 


質問といたしましては、全てのテキストボックスに何も入力されていない場合、この二次元配列はすべて空欄となると思うのですが、それを確認する方法を知りたいです。
1次元の配列なら、

変数名.Integer = 配列名.Count(Function(s)s.Length <> 0)

のようにして、0となればすべて空欄と判断していたのですが、同じように使えず悩んでいます。

ご回答よろしくお願いいたします。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/12 11:47:02
> Table(0,0) = TextBox1_1

= CInt(TextBox1_1.Text) や
= TextBox1_1.Text ではなく、
= TextBox1_1 なのですね?

つまり、TextBox 型(あるいは Control 型)の二次元配列である、と。


> それを確認する方法を知りたいです。
単純に、For Each で十分なのでは?
汎用化したいなら、拡張メソッド化すれば OK かと。

Dim hasData = False
For Each x In table
    If xが空ではない Then
        hasData = True
        Exit For
    End If
Next
MsgBox(If(hasData, "データ有り""全部空っぽ"))



> 1次元の配列なら、
一次元配列なのであれば、使うべきは .All または .Any ですね。.Count ではなく。

投稿者   (社会人)   投稿日時 2022/5/12 11:55:12
ご回答ありがとうございました。申し訳ございません。

=TextBox1_1.Text 

として初期化しております。以後気を付けて質問したいと思います。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/12 12:07:00
だとすると、先の For Each の「If xが空ではない Then」のところを

If Not String.IsNullOrEmpty(x) Then
If Not String.IsNullOrWhiteSpace(x) Then
If x IsNot Nothing Then
If x <> "" Then

などのいずれかにすればよいでしょう。
どれを使うべきかはケースバイケース。

・一度も TextBox1.Text をセットしていない要素は Nothing になります。
・しかし TextBox1.Text は、空であっても Nothing は返しません。"" を返します。
・空白(WhiteSpace)文字だけが入った TextBox を空として扱うかどうか?


> 使うべきは .All または .Any ですね。.Count ではなく。
「すべて空欄かどうか」
「すべて入力済みかどうか」
「空欄がひとつでもあるか」
「入力済みがひとつでもあるか」
を調べたい場合は、All や Any の出番です。

All は「条件に一致しない要素があれば検査を打ち切って False を返す」
Any は「条件に一致した要素があれば検査を打ち切って True を返す」
という仕様です。しかし Count の場合は、常に全件が検査されることになります。

投稿者   (学生)   投稿日時 2022/5/12 13:27:25
ご回答ありがとうございました。解決いたしました。

1つでも要素が入力されているかを確認したかったため、提案していただいた4つ目のもので作業を進めてみたいと思います。

1つ疑問に思い、初心者の疑問だったら申し訳ないのですが、何故1次元の配列なら、All,Anyを利用でき、多次元ならそうではないのでしょうか?


投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/12 14:05:29
> 何故1次元の配列なら、All,Anyを利用でき、多次元ならそうではないのでしょうか?

All や Any は使えませんが、Cast や OfType は使えますよね?


「If foo.All(ラムダ式) Then」という拡張メソッドは、
「If Enumerable.All(foo, ラムダ式) Then」というメソッド呼び出しとして処理されますが、
このメソッドの第一引数は、IEnumerable(Of ) を実装した型でなければいけないわけです。
https://docs.microsoft.com/ja-jp/dotnet/api/system.linq.enumerable.all?

一方 Cast や OfType の場合は、IEnumerable(Of ) ではなく IEnumerable を要求します。
https://docs.microsoft.com/ja-jp/dotnet/api/system.linq.enumerable.oftype?

二次元配列は IEnumerable ですが、 IEnumerable(Of T) では無いのです。

 Dim oneDim As String() = {}
 Dim twoDim As String(,) = {}

 Dim a1 As Array = oneDim
 Dim a2 As Array = twoDim
 Dim b1 As IList = oneDim
 Dim b2 As IList = twoDim
 Dim c1 As IList(Of String) = oneDim
'Dim c2 As IList(Of String) = twoDim  '🚫NG 
 Dim d1 As IEnumerable = oneDim
 Dim d2 As IEnumerable = twoDim
 Dim e1 As IEnumerable(Of String) = oneDim
'Dim e2 As IEnumerable(Of String) = twoDim  '🚫NG 



逆に言えば多次元配列であったとしても、OfType(Of ) なり Cast(Of ) なりを介して
IEnumerable(Of T) に揃えてしまえば、All や Any を使えることになります。

If Not Table.OfType(Of String)().All(AddressOf String.IsNullOrEmpty) Then
    MsgBox("入力されています")
End If



あるいは、二次元配列用の Any 拡張メソッドを自作しておけば、
一次元配列同様に All や Any を使えます。

Public Module Module1
    <System.Runtime.CompilerServices.Extension>
    Public Function All(Of T)(ByVal source As T(,), predicate As Func(Of T, Boolean)) As Boolean
        For Each o In source
            If predicate(o) Then
                Return False
            End If
        Next
        Return True
    End Function
End Module


投稿者   (学生)   投稿日時 2022/5/12 15:03:27
ご回答ありがとうございました。

型の大切さが身に染みてわかりました。

拡張メソッドは使ったことがなかったので使ってみたいと思います、また質問することがあると思いますがよろしくお願いいたします。