[[20190529110811]] 『セルを配列に入れて処理』(skyblue) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『セルを配列に入れて処理』(skyblue)

セルの値を一つ一つ読んで処理するのは遅いので配列に入れて処理したいと考えています。
下記のテストを試みましたがいずれも5行目でエラーが出ます。
正しい方法をご指導ください。

Sub t20190529()
Set aa = ThisWorkbook.Sheets("test2")
Dim p As Variant
p = Range(aa.Cells(1, 5), aa.Cells(29, 5))
p1 = p(1): p29 = p(29)
Stop
End Sub

Sub t201905292()
Set aa = ThisWorkbook.Sheets("test2")
Dim p As Variant
p = Range(aa.Cells(1, 5), aa.Cells(29, 5))
p1 = p(1, 5): p29 = p(29, 5)
Stop
End Sub

< 使用 Excel:Excel2016、使用 OS:Windows10 >


 >5行目でエラー
 5行目ってStopのことですか?
 Stop は実行を中断するステートメントですよ

 中断させたくないのなら不要です。

(白茶) 2019/05/29(水) 11:26


 変数宣言は全ての変数に行ってください。

 話は、それが済んでからです。

(半平太) 2019/05/29(水) 11:27


 ああ。
 5行目って
 >p1 = p(1)

 ここですね。
 配列を初期化してないからか。失礼^^;

(白茶) 2019/05/29(水) 11:28


 Step DebugしてLocal Windowで確かめれば原因はわかるはず。
(seiya) 2019/05/29(水) 11:30

次の従来方法では正しい読み込みが確認できています

Dim p(29)
For i = 1 To 29

    p(i) = aa.Cells(i, 5)
Next
p1 = p(1): p29 = p(29)

(skyblue) 2019/05/29(水) 11:50


私以外の方のアドバイスは重要ですからね。

 とりあえず
 宣言出来ていない変数

 aa (As Worksheet)
 p1
 p29

 (いずれもスコープが不明)

あとこれ

ローカルウィンドウの使い方|ExcelマクロVBA技術解説
https://excel-ubara.com/excelvba4/EXCEL266.html

(白茶) 2019/05/29(水) 11:59


ローカルウィンドウでpの構造を見れば気付けるはずです。

・最初のコードは、2次元配列にセットしているのに1次元で取り出そうとしてる。
・次のコードは、2次元配列に1列分しかセットしていないのに、5列目を取り出そうとしている。
(???) 2019/05/29(水) 12:02


一応、参考として追加しときます

VBA(Excel)高速化対策 -配列化編- - Qiita
https://qiita.com/sango/items/c46a30c62e154077a0c7

(白茶) 2019/05/29(水) 12:05


対策としては、取り出し方を変える手ですが、または代入の仕方を以下にすることもできます。
    Set p = Range(aa.Cells(1, 5), aa.Cells(29, 5))

こうすると、pはRange型オブジェクトになるので、ご提示のような取り出し方もできます。 この場合は、pの変数宣言はVariantではなく、Range型にすべきでしょうね。
(???) 2019/05/29(水) 12:12


???さんありがとうございました
助かりました。
理由は分かりませんが、下記の方法でいずれも成功しました。
特に p1 = p(1): p29 = p(29) で取り出せるのが素晴らしい

世の中にはすごい人がいる。

Sub t20190529()
Set aa = ThisWorkbook.Sheets("test2")
Set p = Range(aa.Cells(1, 5), aa.Cells(29, 5))
p1 = p(1, 5): p29 = p(29, 5)
p1 = p(1): p29 = p(29)
Stop
End Sub

(skyblue) 2019/05/29(水) 12:47


>セルの値を一つ一つ読んで処理するのは遅いので配列に入れて処理したい

>理由は分かりませんが、下記の方法でいずれも成功しました。

エラーがでなくなったとして、
当初の目的は達成したのでしょうか?

(マナ) 2019/05/29(水) 19:16


Set aa = ThisWorkbook.Sheets("test2")

だと、aa には、レンジオプジェクトが格納される。
レンジオプジェクトはセルの集合体である。
よって、

p1 = p(1, 5): p29 = p(29, 5)
p1 = p(1): p29 = p(29)

はセルの値を一つ一つ読んで処理していることになる。

当初の目的は、

>セルの値を一つ一つ読んで処理するのは遅いので配列に入れて処理したい

???

(hatena) 2019/05/29(水) 21:21


あかん、寝ぼけてる。

Set p = Range(aa.Cells(1, 5), aa.Cells(29, 5))

だと P にはレンジオプジェクトが格納される。

です。
(hatena) 2019/05/29(水) 21:23


変数宣言を省略したり、プロパティの省略したりしているので、紛らわしくなる。
省略せずに記述すると、

 Sub t20190529() 
    Dim aa As Sheet
    Set aa = ThisWorkbook.Sheets("test2") 
    Dim p As Range
    Set p = aa.Range(aa.Cells(1, 5), aa.Cells(29, 5)) 

    Dim p1 As Variant, p29 As Variant

    p1 = p.Cells(1, 1): p29 = p.Cells(29, 1) 
    p1 = p.Cells(1): p29 = p.Cells(29) 
    Stop 
 End Sub 

Cells は既定のプロパティなので省略できるので、
p.Cells(1) は p(1) と記述でき、配列のように見えるが、配列ではなくセル参照である。

また、
p1 = p(1, 5)
という書き方は間違いで、
これだと、l1 セルを参照することになる。

(hatena) 2019/05/29(水) 21:45


配列に格納して高速化するなら、下記のようなコードになります。

 Sub test1()
    Dim aa As Worksheet
    Set aa = ThisWorkbook.Sheets("test2")

    Dim p As Variant
    p = aa.Range(aa.Cells(1, 5), aa.Cells(29, 5)).Value

    Dim p1 As Variant, p29 As Variant
    p1 = p(1, 1): p29 = p(29, 1)

    Stop
 End Sub

Value を代入すると2次元配列になる。
Transposeで1次元配列に変換できるので、
下記のようにすることもできます。

 Sub test2()
    Dim aa As Worksheet
    Set aa = ThisWorkbook.Worksheets("test2")

    Dim p As Variant
    p = aa.Range(aa.Cells(1, 5), aa.Cells(29, 5)).Value
    p = WorksheetFunction.Transpose(p)

    Dim p1 As Variant, p29 As Variant
    p1 = p(1): p29 = p(29)

    Stop
 End Sub

(hatena) 2019/05/30(木) 09:40


もう見てくれないと思いますが、私が教えた方法は、Rangeの先頭を(1,1)から(1,5)に変えただけなので、間違って理解されてそうですね。 皆さん、デバッグの要な点を教えていたのに、全然試さなかったように見えます。
 > Set p = Range(aa.Cells(1, 5), aa.Cells(29, 5))

この場合、p(1) は aa.Cells(1,5) であり、p(1,1)。 Rangeの先頭列をずらしただけなので、性能向上は無いですね。(アドレスを代入しただけであり、実体はコピーしていない) ずらしただけだから、p(30)とか、範囲外でも見れてしまうという。 これで用が足りるなら、代入なんてせずに、aa.Cells(1,5) のままで使えば良かった事でしょう。

お薦めだったのは、代入は元のまま使いVariant型の配列にして、あとは取り出し間違いだけ正すこと。

 > p = Range(aa.Cells(1, 5), aa.Cells(29, 5))

これなら、1列だけとはいえ2次元配列なので p(1) とは書けませんが、p(1,1) とすれば、aa.Cells(1,5) が取り出せました。 1次元配列にする意味が無いように思えますし。
5列目から5列目まで取り出したので、出力は1列。 1列しかないのに5列目を取り出そうとしていたから、エラーになっただけ。 その間違いに気づいていれば、「理由は分かりませんが…」なんて事にはなっていなかったはず。
(???) 2019/05/30(木) 13:38


???さんが、最初の回答で、間違いを的確に指摘しているのに、それを理解しようとせずに、
「理由は分かりませんが、」とコードの意味を理解しようとしない、
ということでは、
スキルアップはできないでしょうね。
(hatena) 2019/05/30(木) 13:49

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.