Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10 Home : Excel 2016)
型が一致しない
投稿日時: 21/05/11 10:35:53
投稿者: バルバロッサ

お世話になっております.
あるCSVデータを読みこんで,その各数値を配列を利用して格納して,読み込もうとしています.
CSVのデータは2列あり,1列目は整数値,2列目は実数地になっています.
それぞれを読み込んで,後から呼び出そうとしています.
Sub Sample()
Dim buf As String, tmp As Variant, n As Long
Dim i() As Long
Dim a() As Double
Dim j As Integer, num As Integer
 
    Open "C:\Users\user\Desktop\test.csv" For Input As #1
    n = 0
     
    Do Until EOF(1)
        Line Input #1, buf
        tmp = Split(buf, ",")
        n = n + 1
        i(n) = tmp(0)
        a(n) = tmp(1)
        Loop
    Close #1
     
    For j = 1 To 10 Step 1
        num = InputBox("数字を入力して下さい。")
Debug.Print i(num), a(num)
    Next j
End Sub
 
上記の赤い部分でエラーが出ます.
インデックスが有効範囲にありません.
と出てきます.
 
他にiやaの型宣言をVariantにしてみたり,Dim i As Longと()を外してみたりと試してみたのですが,今度は違うエラーが出てきます.
 
この部分はどのように解消すればよいのか,お教えください.
よろしくお願いいたします.
 

回答
投稿日時: 21/05/11 11:55:02
投稿者: simple

こちらの即効テクニックの記事
「動的配列の初期値を設定する」
https://www.moug.net/tech/exvba/0150126.html
を参照して下さい。
 
"動的配列 Redim Preserve"などがキーワードです。
これらを使って、配列の内容を保持したまま、
配列の大きさを一つずつ広げていくことができます。
 
まずはトライしてみてください。

回答
投稿日時: 21/05/11 13:16:17
投稿者: simple

「動的配列を使う」
https://www.moug.net/tech/exvba/0150109.html
という記事もありました。こちらも参考にしてください。
 
余談ですが、前に挙げた
「動的配列の初期値を設定する」を改めて読むと、変な例文(Sample1)になっていますね。
Preserveを使わないRedimになっているわけだが、普通こうしたことはしませんね。
配列の内容こそが大事なので。
そもそも、個数を調べたいだけなら、
結果を配列に入れる必要はなく、カウンタ変数ひとつで済むわけですから。
# 以前(大昔)、即効テクニックの記事を総ざらいで検証するスレッドを建てたことがあった。
# その時には、そこは議論になっていなかった気がする。
# 重点が初期値にあるということで、昔はもっと大人だったのかなww

投稿日時: 21/05/11 15:32:11
投稿者: バルバロッサ

Simple様
大変ありがとうございました.
始めに,Redimだけで作ってみたのですが,エラーはなく通ったのですが,結果がすべて0になってしまっていました.
そこで,今度はPreserveを入れてやってみました.
Sub Sample()
Dim buf As String, tmp As Variant, n As Long
Dim i() As Long
Dim a() As Double
Dim j As Integer, num As Integer
 
    Open "C:\Users\user\Desktop\test.csv" For Input As #1
    n = 0
     
    Do Until EOF(1)
        Line Input #1, buf
        tmp = Split(buf, ",")
        n = n + 1
        ReDim Preserve i(n)
        ReDim Preserve a(n)
        i(n) = tmp(0)
        a(n) = tmp(1)
        Loop
    Close #1
     
    For j = 1 To 10 Step 1
        num = InputBox("数字を入力して下さい。")
Debug.Print i(num), a(num)
    Next j
End Sub
出来たのですが,途中でオーバーフローを起こしてしまいました.
今回のデータとしては,テスト用として,Excelの最終行(1048576行)までの数値を入れて,それをCSVで保存してそのデータで検証しました.
本来のデータはもっと長いCSVデータになります.
型宣言もLongにしているので,オーバーフローしないと思っていたのですが,配列に入れる限界なのでしょうか?
 
よろしくお願いいたします.

回答
投稿日時: 21/05/11 15:40:46
投稿者: simple

オーバーフローしたときの、各種の変数の値は確認されましたか。
n,tmpの値を教えてください。

回答
投稿日時: 21/05/11 15:40:51
投稿者: WinArrow
投稿者のウェブサイトに移動

> Do Until EOF(1)
の前に
 
        ReDim i(n)
        ReDim a(n)
 
を記述してみてください。

回答
投稿日時: 21/05/11 15:47:50
投稿者: WinArrow
投稿者のウェブサイトに移動

注意事項
  
ReDim a(n)
は、ReDim a(0 to n)
と同じことです。
つまり、indexが 0 からになります。
  
n = n +
  
になっているので
ReDim a(1 To 1)
の方がよいですね・・・
 
但し、その場合
> ReDim Preserve i(n)
> ReDim Preserve a(n)

        ReDim Preserve i(1 To n)
        ReDim Preserve a(1 To n)
に変更が必要です。

回答
投稿日時: 21/05/11 16:58:22
投稿者: WinArrow
投稿者のウェブサイトに移動

オーバーフローの原因は
 
もしかして
 num As Integer
 
かも?

投稿日時: 21/05/11 18:44:15
投稿者: バルバロッサ

simple様、WinArrow様
 
沢山のご意見誠にありがとうございました。
まず、n、i、a、tmpの様々な変数に関してオーバーフローを検証しました。
最後まで読めていました。
 
そこで、次に
Sub Sample()
Dim buf As String, tmp As Variant, n As Long
Dim i() As Long
Dim a() As Double
Dim j As Integer, num As Integer
Dim k As Integer
  
    Open "C:\Users\user\Desktop\test.csv" For Input As #1
    n = 0
      
     
    ReDim i(1 To 1)
    ReDim a(1 To 1)
     Do Until EOF(1)
        Line Input #1, buf
        tmp = Split(buf, ",")
        n = n + 1
        ReDim Preserve i(1 To n)
        ReDim Preserve a(1 To n)
' ReDim Preserve i(n)
' ReDim Preserve a(n)
        i(n) = tmp(0)
        a(n) = tmp(1)
        Loop
    Close #1
      
    For j = 1 To 10 Step 1
        num = InputBox("数字を入力して下さい。")
Debug.Print i(num), a(num)
    Next j
         
End Sub
としてみました。
これでも同じ結果でした。
最後に
Dim j As Integer, num As Long
に変更しました。
すると、オーバーフローが消えました。
 
つまり、CSVのデータはきちんと配列に組み込まれていたのですが、打ち込むnumがIntegerだったので、オーバーフローしておりました。
 
ものすごく勉強になりました。感謝感謝です。
 
ありがとうございました。