[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『For EachとFor Nextの使い方』(よん)
こんにちは
For Eachが一番早いよ!って感じの記事を読んだときに、For NextやDo Loopと違って毎ループでセルを直接参照しないから早いんだよって感じの説明が書いてあったのですが、事前にvariant型にセル範囲をぶち込んでからFor Nextをするのと何が違うんや?と思ったので質問させていただきました。
よろしければ回答お願いします。
< 使用 Excel:Excel2007、使用 OS:WindowsVista >
特に検証していないですが、頭の中で考えたこと。
「For Eachが一番早いよ!」と言う話自体、ピンと来ないですね。
For Each ・・In ○○
○○がどうなっているかですよね。 そこがRangeオブジェクトなら、結局、セルを直接参照しているんじゃないですか?(してないの? 自信ないですけど) そこがVariant型にぶち込んである配列だったら、どう言う結論になるんですか? (それもFor Eachなんですけど。)
速い/遅いと言ったって、読み出し処理ですよね。 目くじら立てるところでもない気がします。
速度の問題は、書き込み処理で真価が問われるんだと思いますけどねぇ・・
(半平太) 2020/10/26(月) 13:10
単純にセル位置をわずかな行、列計算しているかしてないかだけだと思いますけど? Range で書くより Cell で表現した方が速いとも聞くし。 添え字使った方がイメージしやすいし。
おまけ
Sub aaaa() Dim Tb(1 To 5) As Variant Dim vv As Variant For Each vv In Tb i = i + 1 vv = i Next Range("A1:E1").Value = vv End Sub
Sub bbb1() Dim vv Range("A3:E5").ClearContents For Each vv In Range("A3:E5") i = i + 1 vv = i Next End Sub
Sub bbb2() Dim vv Range("A3:E5").ClearContents For Each vv In Range("A3:E5") i = i + 1 vv.Value = i Next End Sub
Sub bbb3() Dim vv As Range Range("A3:E5").ClearContents For Each vv In Range("A3:E5") i = i + 1 vv = i Next End Sub
Sub bbb4() Dim Tb As Variant Dim vv As Variant Range("A3:E5").ClearContents Tb = Range("A3:E5").Value For Each vv In Tb i = i + 1 vv = i Next Range("A3:E5").Value = Tb End Sub
(Why) 2020/10/26(月) 13:43
>For Eachが一番早いよ! 前提が省略されすぎていてなんとも。
『○○するときには、For Eachが一番早い』の○○部分はなんですか? その記事はどうやったら見れますか? (´・ω・`) 2020/10/26(月) 14:03
書き込み方法だけの話だと思いますけど・・・ 試してみたところ、 書き込み速度の差 > 参照速度 の影響が強そう For Eachでtbl回すのって見たことないですね・・・
Sub mktestdate() Dim i As Long Dim tbl(1 To 10000, 1 To 1) Randomize For i = 1 To 10000 tbl(i, 1) = Int(Rnd() * 1000 + 1000) Next i Range("A1:A10000").Value = tbl End Sub Sub aa() Dim t As Double Dim r As Range Dim tt As Variant Dim r1(1 To 10000, 1 To 1) Dim tbl As Variant Dim i As Long Dim msg As String t = Timer For Each r In Range("A1:A10000") r.Value = r.Value + r.Value Next r msg = "for each 都度書込: " & Timer - t & "ミリ秒" & vbCrLf
i = 1 t = Timer For Each r In Range("A1:A10000") r1(i, 1) = r.Value + r.Value i = i + 1 Next r Range("A1:A10000").Value = r1 msg = msg & "for each 一括書込: " & Timer - t & "ミリ秒" & vbCrLf
i = 1 t = Timer tbl = Range("A1:A10000").Value For Each tt In tbl tbl(i, 1) = tt + tt i = i + 1 Next tt Range("A1:A10000").Value = tbl msg = msg & "for each tbl都度書込: " & Timer - t & "ミリ秒" & vbCrLf
t = Timer tbl = Range("A1:A10000").Value For i = 1 To 10000 Cells(i, "A").Value = Cells(i, "A").Value + Cells(i, "A").Value Next i msg = msg & "for 都度書込: " & Timer - t & "ミリ秒" & vbCrLf
t = Timer tbl = Range("A1:A10000").Value For i = 1 To 10000 tbl(i, 1) = tbl(i, 1) + tbl(i, 1) Next i Range("A1:A10000").Value = tbl msg = msg & "for 一括書込: " & Timer - t & "ミリ秒" & vbCrLf
MsgBox msg End Sub
(稲葉) 2020/10/26(月) 14:16
>For Eachが一番早いよ!って感じの記事を読んだ
あぁ、その噂は聞いたことがありますが、
結局その後、その値なりオブジェクトなりをどう使うかが重要で、
ループの書き方で差はないようです。
>事前にvariant型にセル範囲をぶち込んでからFor Nextをするのと何が違うんや? セルの値を参照するだけなら、変数に代入してからループした方が速いですし、 セルそのものを代入するのなら、2度手間ですね。まぁ、時間は変わりませんが。
噂は噂ですし、バージョン等でも違うかも知れません。
結局は自分で実験してみて、確認する方が確実です。
たぶんこういう比較をしてFor Each〜nextの方が速いと言われてると思います。
Option Explicit
Sub test1()
Dim c As Range Dim v Dim t
t = Timer
For Each c In Columns(1).Cells v = c.Value Next
MsgBox Timer - t End Sub
Sub test2()
Dim i As Long Dim v Dim t
t = Timer
For i = 1 To Rows.Count v = Cells(i, 1).Value Next
MsgBox Timer - t End Sub
Sub test3()
Dim i As Long Dim vv Dim v Dim t
t = Timer
vv = Columns(1).Value For i = 1 To UBound(vv, 1) v = vv(i, 1) Next
MsgBox Timer - t End Sub
>Range で書くより Cell で表現した方が速いとも聞くし。
僕はCellsよりRangeの方が速いって聞きましたけど、
どうなんでしょうね。
Valueプロパティも省略した方が速いって聞きますし、
(まっつわん) 2020/10/26(月) 15:13
ここら辺の記事が元でしょうか? http://officetanaka.net/excel/vba/speed/s5.htm
セルへのアクセスの回数を減らすのが、ループの方法より影響が大きいので同列に扱わない方が よい気はしますが。 (QS) 2020/10/26(月) 16:27
http://blog.starbug1.com/archives/568
書き方が悪いだけの場合もあるので、速度の話をするときは「前提」が大事です。
(通りすがり) 2020/10/26(月) 16:57
ええと、私のコードは、列神話がはびこっているみたいなので、 その教訓として、For Each vv in 配列 で配列に書き込めない? と、言うのを知ってもらうだけの物。 なんか、VBでは出来るみたいなんですが。 二十年ぐらい前?大学の教授さんとかが、For Each は、速い、 For Each で、配列の初期化と言うのを雑誌で見て、それを真似たら、VBAでは出来なかったので。
>僕はCellsよりRangeの方が速いって聞きましたけど
あれ?Rangeだったっけ?覚えてないと。 後で書き込もうとしていたので、そうかもしれないですね。
(Why) 2020/10/26(月) 21:29
>その教訓として、For Each vv in 配列 で配列に書き込めない? これは便利かもですね tbl = [a1:d5].value for i = 1 to 10 for each c in index(tbl,i,0) c = c + 1 next c next i [a1:d5].value = tbl
ためしてないですが、こんな感じの使い方もできます? 配列にindexの場合は、参照渡しじゃなくて、値渡しになってしまいますかね?
余談になりますが [[20200811090110]] 『「Dictionary」からの取出し』(T20) こっちでも半平太さんとγさんに教えてもらって実験してみたので 質問者さんの参考になれば。 (稲葉) 2020/10/26(月) 22:54
VBSでINDEXなかった・・・ vbsからxlApp作ってIndexから1次配列にする? そこまでしてForEach使う必要もないですよね。
(稲葉) 2020/10/27(火) 09:07
本題については、議論されているので、周辺話題を。
officetanakaさんのサイト「VBA高速化テクニック」 http://officetanaka.net/excel/vba/speed/ に一度目を通されると有益かと思います。
RangeとCellsとでは、Cellsのほうが早いらしいが、 田中さんは、正鵠を射たことを書かれている。 | どちらを使うかは速度差で決めることじゃなく、必然性がすべてです。 | Rangeを使うべき場面だったら、たとえ多少遅くたってRangeを使うべきだし、 | Cellsを使うべきケースだったら迷わずにCellsを使うべきです。 ま、そのとおりですな。
Collectionについて言及がありましたので、少し補足を。 indexを経由してitemを取りに行っているのに対して、 For each は、itemを直接走査するので、その分早くなります。
なお、Collectionより色々な面で拡張されているのがDictionaryで、 私はもっぱらこちらを使いますが、これには、For Each しかありません。 Collectionとの違いは、CollectionがItemを走査するのに対して、 DictionaryはKeyを走査することです。 (もっともKey配列に対してindexでアクセスすることはできますが、 たぶん若干なりとも遅くなるのではないかと思います。)
For Eachというiteratorが定義されている場合は、概ねこちらを使ったほうが早いです。 そのための機能ですから。 (γ) 2020/10/27(火) 09:53
自分が見つけた記事はこちらで、以下の文言に違和感を感じたので質問させてもらいました。
For Each構文は、ループに入るタイミングで、あらかじめ作業対象のセルの参照の集合を、メモリに読み込みます。
そして、その読み込まれた集合に対して処理をしていきます。
一方、For Next構文、Do Loop構文では、「Range(“C” & c)」といった構文に来る都度、改めて、そこで言われているセルがどこなのか?ということを調べにいきます。
その分のオーバーヘッド(IT用語: 間接的・付加的に必要となる処理とそれにより発生する負荷の大きさ)のせいで、時間がかかってしまうんですね。
この部分を読んで、
Sub test()
Dim r() As Long, c As Long, n As Long
ReDim Preserve r(9, 0)
For c = 2 To 11
n = c - 1
r(c - 2, 0) = n
Next c
Range("A2:A11").Value = r
End Sub
こんな感じだとForNextでも速度変わらないんでは?
と思った次第です。
初めの質問で前提が抜けていて申し訳ないです。
これも結局演算自体の処理というよりも書き込み速度が大きく影響してると思ったらいいのかなぁと何となく理解はできたと思います。
結局どっちを使ったらいいのってとこは、実用レベルだと誤差の範囲だけれど最効率を目指すならば走査しやすいほうだと考えればいいって感じなんですかね?
(よん) 2020/10/27(火) 11:14
(γ) 2020/10/27(火) 11:43
記事読ませていただきました。 すこし古い記事なので、今のバージョンとは違うのかもしれませんが、 Valueプロパティを読み書きする場合の速度については、 少しだけ For Eachが早いのは本当だと思います。 余計な処理がいらないので。
>実用レベルだと誤差の範囲だけれど最効率を目指すならば
最効率を目指すならば、全体の最適化が重要なので、 これだけでは決まりませんね。 (´・ω・`) 2020/10/27(火) 13:08
ルールが無かったので、自身でコーディングルールを作りました。
1カ月もそのコードに触れていないと忘れますから。
For Each 対象が全ての場合
For Next 繰り返す数が決まっている場合
Do Loop フラグが立たない限り繰り返す場合
見たいに決めておくと、コードを見たとき大枠が読めるので便利ですよ。
(tkit) 2020/10/27(火) 13:47
>事前にvariant型にセル範囲をぶち込んでからFor Nextをするのと何が違うんや?と思った
・・で、何が違うのか分かったんですか?
紹介されたサイトのコードは、「論外」とも言われた程のしょうもない代物なんですけど。
(半平太) 2020/10/28(水) 13:02
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.