2016-09-14 27 views
0

以下のコードでは、2つの日付値をチェックしようとしています。存在する場合は、列BGの間の日数を計算します。存在しないか結果が0より小さい場合は、行を削除します。VBA Forループ反復問題

私が抱えている問題は、いったん行を削除すると、次のIを使用し、行のすぐ後をスキップすることです。例:行1 & 2に日付がありません。行1が削除されます。行2は行1にプッシュアップされ、次に私は2行目になり(3だった)、行2の結果はスキップされます。 i = i-1を使用すると、プログラムがクラッシュするようです。また、コードを効率的にして、アイテムのすぐ後を繰り返し処理できるようにするための方法はありますか?

Sub Func4() 

Dim N As Long, i As Long, j As Long, cnt As Long, date1 As Date, date2 As Date, date3 As Long ', iold As Long 

N = Cells(Rows.Count, "A").End(xlUp).Row 

j = 2 
cnt = 0 
For i = 2 To N 'main 
    j = j + 1 
    'iold = i 
    If Not IsEmpty(Cells(i, "AB").Value) And Not IsEmpty(Cells(i, "AE").Value) Then 
     date1 = Cells(i, "AB").Value 'AB=Entry Date 
     date2 = Cells(i, "AE").Value 'AE=Rec'd 
     date3 = Work_Days(date2, date1) 
     cnt = cnt + 1 

     If date3 >= 0 Then 
      Cells(i, "BG").Value = date3 

     Else 
      Rows(i).EntireRow.Delete 
      'i = i - 1 'HERE 
     End If 
    Else 
     Rows(i).EntireRow.Delete 
     'i = i - 1 'HERE 
    End If 

    'End If 
    'If i = iold Then 
Next i 

'Else 
'Next 
'End If 

End Sub 

決議WORKINGのANSWER:

Sub Func4() 
    Dim N As Long, i As Long, j As Long, cnt As Long, date1 As Date, date2 As Date, date3 As Long 
    N = Cells(Rows.Count, "A").End(xlUp).Row 
    j = 2 
    For i = N To 2 Step -1 
      j = j + 1 

     If Not IsEmpty(Cells(i, "AB").Value) And Not IsEmpty(Cells(i, "AE").Value) Then 
      date1 = Cells(i, "AB").Value 'AB=Entry Date 
      date2 = Cells(i, "AE").Value 'AE=Rec'd 
      date3 = Work_Days(date2, date1) 
      cnt = cnt + 1 
       If date3 >= 0 Then 
        Cells(i, "BG").Value = date3 

       Else 
        Rows(i).EntireRow.Delete 
       End If 
     Else 
     Rows(i).EntireRow.Delete 
     End If 
     Next i 

End Sub 
+4

。 – Comintern

+2

コミンテルンが言ったように 'For i = N To 2 Step -1' –

+0

チップをありがとう!私はそのように考えなかった。私はそれが完璧に動作するように見えた!あなたの簡単な回答を回答として提出してください。私はあなたにポイントを与えるでしょう! – Josh

答えて

0

最初の問題を解決するには、ループを逆に実行できます。このようにして、削除は、既に反復された行だけをシフトします。

For i = N To 2 Step -1 

2番目の質問は少し開いています。このガイドでは、あなたのコードを高速化する方法についていくつかの提案があります:

http://datapigtechnologies.com/blog/index.php/ten-things-you-can-do-to-speed-up-your-excel-vba-code/

あなたのコードに関連する私に最も目立つガイドからいくつかの項目を。

  • 「無効シート画面の更新」

置きますが、多数の行が削除されている予想される場合は特に、あなたのコードを中心に、以下。

Application.ScreenUpdating = False 
    Application.ScreenUpdating = True 
  • 配列に列「AB」と「AE」を読んで、そして上の細胞ではなく、それを反復処理することにより、

これは最高の達成されるだろう「ワークシートへの過度のトリップを回避」シート。ここではそれを達成するためのソリューションです:あなたが行を削除している場合は、逆方向にループする必要がある

Fastest way to read a column of numbers into an array

Dim Ar as Variant 

Ar = Sheets("Sheet").Range("A1:A10000").Value 
-1

Do until i > Nに変更For i = 2 To NLoopNext iは、その後、削除行

+0

要点は、ループ内の行を削除すると項目がシフトして、何回か繰り返していることになります。ループされた項目リストから項目を削除するときは、常に逆にループします。 –

+0

ほぼすべての状況で、逆順でループする必要がありますが、常に例外ではないことに同意します。 – Jeremy

+0

例外は常にありますが、ベストプラクティスです。反復処理中のコレクションからアイテムを削除するときは、以上。それは私から取ってください。これは、Office Object Modelに対して開発を始めた人が主な間違いの1つです。だから、Office開発者が別の方法でやるように教えるように注意してください。 –

0

まず下の行をコメント(事前i = 2を割り当てることを忘れないでください)コメントはCominternとShai Radoのコメントで答えた:

範囲から項目を削除すると、残りの項目が元に戻ります。リバースループすることにより、削除されたアイテムは残りのアイテムに影響しません。物事をスピードアップする

2番目の質問、このブログの記事をお読みください。

https://blogs.office.com/2009/03/12/excel-vba-performance-coding-best-practices/

、特に一部の下で: 読む/回の操作で細胞の大きなブロックを書く

それがします配列内のデータを処理する場合は、このブログの例に示すように、データを配列に読み込んで書き戻すほうが速くなります。特に何千ものアイテムがあれば、これは重要です!