
No.3ベストアンサー
- 回答日時:
こんにちは。
KenKen_SP です。ループ処理は必須ですね。ただ、時間を短縮させることは可能です。
【POINT】
1. UsedRange や CurrentRegion、SpecialCells などで処理対象のセルを
限定させ、ループ数を減らす
全てのセルが選択された状態で考えてみます(Selection が Cells のとき)
For Each c in Selection ...といったコードは良く見かけますが、この
ままでは、65536×256 のループ処理になります。通常、処理が必要なのは、
何らかのデータが存在するセルのみなので、
For Each c in Intersect(Selection,Activesheet.UsedRange)
のようにすると、ループ回数が激減するはずです。同様に、置換処理などでは
数式のあるセルでは置換処理は無意味ですから、
For Each c In Selection.SpecialCells(xlCellTypeConstants, xlNumbers Or xlTextValues)
として定数のセルのみループさせます。数式の置換なら数式のあるセル
だけですね。
ループ回数を減らすだけで、随分と処理速度が改善します。
2. オブジェクトへの参照を減らす
Excel VBA で処理速度を落とす要因のひとつに、オブジェクトへの参照
があります。これをなるべく減らす様にコーディングすると良いでしょう。
具体的には配列を使用します。
For Each c in Selection で Range コレクションをループさせた場合、
ループの度にセルへの参照が行われます。これが非常に遅い。
オブジェクトの参照が遅いのは、数多くのプロパティーを同時に取得する
からですね。例えば、セルのフォントや罫線、色、書式等々。
全セル選択時だとフリーズ、、または非常に長い時間がかかります。
大半の処理で必要なのは Value プロパティーだけだったりします。
では、配列を使用してみます。
Buffer = Selection.Value
For Each vntElement in Buffer
Next
この場合、セルの参照は1回だけで、取得するプロパティーは Value のみ
です。
全てのケースで配列が有効なわけではありません。特に、セルの選択範囲
が飛び飛びの場合だと Areas コレクションでブロック毎に切り分け処理が
必要になりますし。
以上を検証するために、7万セル(10,000行×7列)に "aaa " のデータをセットし、
実際に計測してみました。
左が Test1 で、右が Test2 の結果です。単位はミリ秒。ロジックの違いで
10倍以上の差が発生します。
Test1 Test2
1回目:= 1038 10427
2回目:= 1039 10427
3回目:= 1043 10439
4回目:= 1034 10424
5回目:= 1041 10456
Sub Test1()
Dim rngTarget As Range
Dim Buffer As Variant
Dim lngRowCnt As Long
Dim lngColCnt As Long
Dim i As Long, j As Long
Set rngTarget = Range("A1").CurrentRegion
Buffer = rngTarget.Value
lngRowCnt = UBound(Buffer)
lngColCnt = UBound(Buffer, 2)
For i = 1 To lngRowCnt
For j = 1 To lngColCnt
Buffer(i, j) = Trim$(Buffer(i, j))
Next j
Next i
rngTarget.Value = Buffer
Set rngTarget = Nothing
End Sub
Sub Test2()
Dim rngTarget As Range
Dim C As Range
Set rngTarget = Range("A1").CurrentRegion
For Each C In rngTarget
C.Value = Trim$(C.Value)
Next
Set rngTarget = Nothing
End Sub
KenKen_SPさん、いつもありがとうございます。
配列ですか。すごい方法があるんですね!驚きました。
早いです!ありがとうございました。助かりました。
ひとつだけいいですか?
C.Value = Trim$(C.Value)の$は何でしょうか?
Stringかなとも思いましたが、結果は数値ででますし、これを取っても結果は変わらなかったので不思議に思いました。
No.4
- 回答日時:
> C.Value = Trim$(C.Value)の$は何でしょうか?
あら? セルへのデータセットなので、この場合は逆効果ですね、すいません。
それは C.Value = Trim(C.Value) の方が良いです。
$ の意味ですが、Trim 関数をヘルプで調べると、
[Excel VBA ヘルプ引用]
指定した文字列から...(略)...先頭と末尾の両方のスペース (Trim) を削除
した文字列を表すバリアント型 (内部処理形式 String の Variant) の値を返
します。
とあるように、Trim 関数の戻り値は Variant 型です。これに $ をつけて Trim$
とすると、戻り値の型は String 型になります。この意義ですが、
Trim 関数の戻り値を String 型の変数に代入するときは、Trim$ 関数の
方が高速に動作する
です。同様に Left$、Right$、Mid$、Replace$、String$ ...等々もあります。
VB(VBA)は、プログラムの敷居を低くするためデータ型を意識しなくとも、
バックグラウンドで適切な型に変換する機能(自動キャスト)が備わっています。
# ゆえに、「VB にはデータ型がない、変数を宣言しなくても良い」という
# 誤解を生んでいますが。
しかし、VB もプログラム言語ですから内部的には厳密なデータ型が存在します。
データ型を意識しないコードを書いても、それが動作するのは、
「VB が裏で必死で頑張ってくれるから」
に過ぎません。例えば、次のようなコード。
Dim strDATA As String '<-- String 型で宣言
strDATA = Trim("あああああ")
Trim 関数の戻り値は Variant 型なので、String 型の変数に直接代入できません。
そこで、VB は頑張ります。
1. どうも Variant のままでは代入できないらしい
2. では、どの型に変換したら良いか調べよう
2. どうも String 型がよいらしい
3. では Variant --> String のデータ型変換を行おう
4. 変数へ代入
なんて作業が裏では発生しています。
確かに、プログラムの敷居は低くなりますが、これでは余計な型変換の作業が
発生する分、実行速度は低下しますね。これを回避するなら、
Dim strDATA As String '<-- String 型で宣言
strDATA = Cstr(Trim("あああああ"))
とします。これで、VB が「どの型に変換すべきか?」という作業から開放され、
実行速度が向上します。
さらに、Trim には Trim$ 関数という結果を String 型で返す専用関数が用意
されてます。
Dim strDATA As String '<-- String 型で宣言
strDATA = Trim$("あああああ")
これで、「適切な型に変換する」という作業から開放されました。結果として
実行速度は向上します。なお、
vntDATA = Trim(Range("A1").Value)
のように、セルに何型のデータが入力されるか、固定できない場合は、逆効果
になるので、$ はつけません。
上記のように「ごく短い」コードでは、このような細かい注意で体感できるほど
の処理速度の向上はありませんが、例えば次のコードではどうでしょうか?
Dim strDATA As String '<-- String 型で宣言
Dim i As Long, j As Long, k As Long
For i=1 to 10000
'処理1
For j=1 to 5000
'処理2
For k=1 to 30
'処理3
strDATA = Trim("あああああ") '※
strDATA = Replace ~
Next k
Next j
Next i
ごく普通にでてきそうなコードですね。。。
注意してほしいのは、※記号の部分が 10000 × 5000 × 30 回実行される点です。
上述の「VBが裏で頑張る余計な作業」がこれだけ発生することになるんです。
これでは、遅くなるのは「当たり前」です。VB が「遅い」という前にコードが
悪いといった方が良いでしょう。
長々と書きましたが、以上の訳で、Trim は文字列を扱う場合がほとんどですから、
$ を癖みたいにつけてしまうんです。
今回はセルへの代入なので、逆効果ですが。
変数の宣言をしないと速度が落ちる、、だから、ちゃんと宣言しなさい、、
と良く言われる理由のひとつです。
No.2
- 回答日時:
Sub test01()
Worksheets("Sheet1").Range("A1:A5") = Trim(Worksheets("Sheet1").Range("A1:A5"))
End Sub
ができないので
ForNextかForEachNextでセルごとに繰り回しをせざるを得ないと思います。
ありがとうございます。
Sub test01()
Worksheets("Sheet1").Range("A1:A5") = Trim(Worksheets("Sheet1").Range("A1:A5"))
End Sub
が出来ればいいんですけどねえ。
No.1
- 回答日時:
下記の例のようなコードで時間が掛かりすぎるということでしたら、
1.他のソフトで前後のスペースを取り除いてから Excel に取り込む
2.外部からデータを取り組む際に何らかの細工をする
のどちらかになると思います。
(例)
Public Sub Test1()
Dim MyRange As Range
For Each MyRange In Range("A1").CurrentRegion
MyRange.Value = Trim(MyRange.Value)
Next
Set MyRange = Nothing
End Sub
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Excel(エクセル) エクセルの数式で教えてください。 1 2023/02/02 10:20
- Visual Basic(VBA) Excel VBA 最終行を取得しVlookup関数をコピーする方法をコーディングで教えてください。 3 2023/05/11 13:14
- Visual Basic(VBA) 列と行の名前(重複あり)が交差するセルに、データを入力したい 2 2022/06/25 22:42
- Visual Basic(VBA) vba 等間隔の列に対しての計算 6 2022/05/17 20:15
- Visual Basic(VBA) 3つのプロシージャをまとめたら実行時エラー発生で対応不能 6 2022/05/17 01:47
- Visual Basic(VBA) VBA 「,」・空白・カタカナ等の複数条件のマクロ 2 2023/08/23 11:57
- Visual Basic(VBA) 複数の列の値を結合して別の列へ返す 2 2022/08/06 16:07
- Visual Basic(VBA) 特定の文字を簡単な操作で半角スペースに変換するか削除したい 2 2022/11/01 10:35
- Visual Basic(VBA) vbaエクセルマクロ RemoveDuplicatesについて RemoveDuplicatesを使 3 2023/02/28 01:13
- Visual Basic(VBA) 列と行の名前(重複あり)が交差するセルに、データを入力したい 3 2022/06/12 11:17
このQ&Aを見た人はこんなQ&Aも見ています
-
エクセル:マクロ「Application.CutCopyMode = False」って?
Excel(エクセル)
-
VBA スペースが入力されていても、空白セルと判断する方法
Excel(エクセル)
-
VBAでの Replace関数で、ワイルドカードは使えないのでしょうか?
Visual Basic(VBA)
-
-
4
WorkBooksをオープンさせずにシートにコピーしたい【EXCEL VBA】
Excel(エクセル)
-
5
「Columns(A:C")」の列文字を数字にして表記したい"
Excel(エクセル)
-
6
2つ以上の変数を比較して最大数を求めたい
Word(ワード)
-
7
UserForm1.Showでエラーになります。
工学
-
8
文字列からタブコードを取り除きたい
Visual Basic(VBA)
-
9
エクセルのエラーメッセージ「400」って?
Visual Basic(VBA)
-
10
エクセルマクロで特定の範囲が空白という条件
Excel(エクセル)
-
11
【Excel VBA】マクロでExcel自体を終了させたい
Excel(エクセル)
-
12
VBAのコマンドボタンの文字列の改行方法は?
Visual Basic(VBA)
-
13
VBA(エクセル)で自動的にボタンをクリックさせるには
その他(プログラミング・Web制作)
-
14
VBAで指定範囲内の空白セルを左詰めで一括削除したいのですが
Visual Basic(VBA)
-
15
CSV形式にすると出てくる空白を消したいです。
その他(Microsoft Office)
-
16
Cellsのかっこの中はどっちが行と列なの?
Visual Basic(VBA)
-
17
VBAでブックを非表示で開いて処理して閉じる方法
Excel(エクセル)
-
18
複数の条件に合う行番号を取得するには
その他(Microsoft Office)
-
19
VBAでセル入力の数式に変数を用いたい
Excel(エクセル)
-
20
【Excel VBA】CSV取込時、数字の先頭の0を消えないようにするには?
Excel(エクセル)
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
貼り付けで複数セルに貼り付けたい
-
(Excel)数字記入セルの数値の後...
-
セルをクリック⇒そのセルに入力...
-
エクセルで指定したセルのどれ...
-
エクセルのセルの枠を超えて文...
-
エクセル セルの中に縦線が入っ...
-
枠に収まらない文字を非表示に...
-
Excelで数式内の文字色を一部だ...
-
対象セル内(複数)が埋まった...
-
Excelで教えてください。 バー...
-
Excelで住所を2つ(町名迄と番...
-
エクセル オートフィルタで絞...
-
【エクセル】IF関数 Aまたは...
-
エクセルの書式設定の表示形式...
-
excelの特定のセルの隣のセル指...
-
Excel2003 の『コメント』の編...
-
Excel 例A(1+9) のように番地の...
-
数式を残したまま、別のセルに...
-
EXCEL VBA セルに既に入...
-
エクセルの一つのセルに複数の...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Excelについての質問です 並べ...
-
【マクロ】アクティブセルの2...
-
スプレッドシートで複数のプル...
-
excelで日付関数の文字列変換の...
-
エクセルで指定したセルのどれ...
-
貼り付けで複数セルに貼り付けたい
-
枠に収まらない文字を非表示に...
-
セルをクリック⇒そのセルに入力...
-
エクセルの一つのセルに複数の...
-
数式を残したまま、別のセルに...
-
(Excel)数字記入セルの数値の後...
-
Excel 例A(1+9) のように番地の...
-
対象セル内(複数)が埋まった...
-
エクセルの書式設定の表示形式...
-
EXCEL VBA セルに既に入...
-
excelの特定のセルの隣のセル指...
-
エクセルのセルの枠を超えて文...
-
Excelでのコメント表示位置
-
エクセル オートフィルタで絞...
-
Excelで数式内の文字色を一部だ...
おすすめ情報