이 글을 도움말을 번역한 글입니다.
For Each...Next 문
배열 또는 컬렉션의 각 요소에 대해 문 그룹을 반복합니다.
Syntax
For Each element In group
[ statements ]
[ Exit For ]
[ statements ]
Next [ element ]
element : 필수. 컬렉션 또는 배열의 요소를 반복하는 데 사용되는 변수입니다. 컬렉션의 경우 요소는 Variant 변수, 일반 개체 변수 또는 특정 개체 변수만 사용할 수 있습니다. 배열의 경우 요소는 Variant 변수만 가능합니다.
group : 필수. 개체 컬렉션 또는 배열의 이름입니다.(사용자 정의 유형의 배열 제외).
statements : 선택 사항입니다. 그룹의 각 항목에 대해 실행되는 하나 이상의 문입니다.
For Each...Next 문은 컬렉션의 각 개체 또는 배열의 각 요소에 대해 문 블록을 반복합니다. Visual Basic은 루프가 실행될 때마다 자동으로 변수를 설정합니다. 예를 들어, 다음 절차는 A1~A10 범위에 있는 모든 셀의 값에 10을 더합니다.
예제 코드 - 1
Sub Add10ToAllCellsInRange()
Dim rng As Range
For Each rng In Range("A1:A10")
rng.Value = rng.Value + 10
Next
End Sub
다음 코드에서는 Dictionary를 사용하여 과일 이름과 각 과일의 개수를 저장합니다.그리고 For Each Next 문을 사용하여 Dictionary의 모든 요소를 반복하면서 각 요소의 값을 2배로 변경하고, 변경된 값들을 출력합니다.
예제 코드 - 2
Sub ModifyDictionaryValues()
Dim dict As Object ' Dictionary 개체 선언
Set dict = CreateObject("Scripting.Dictionary") ' Dictionary 개체 생성
' Dictionary에 키와 값을 추가
dict.Add "apple", 10
dict.Add "banana", 20
dict.Add "orange", 30
' 변경 전 값 출력
Debug.Print "=== Before Modifications ==="
Dim key As Variant
For Each key In dict.Keys
Debug.Print key & ": " & dict(key)
Next key
' Dictionary의 각 요소 값 변경
For Each key In dict.Keys
dict(key) = dict(key) * 2 ' 각 값을 2배로 변경
Next key
' 변경 후 값 출력
Debug.Print "=== After Modifications ==="
For Each key In dict.Keys
Debug.Print key & ": " & dict(key)
Next key
End Sub
' 결과 출력
' === Before Modifications ===
' apple: 10
' banana: 20
' orange: 30
' === After Modifications ===
' apple: 20
' banana: 40
' orange: 60
셀 범위를 통한 반복
For Each...Next 루프를 사용하여 범위 내의 셀을 반복합니다. 다음 프로시저는 Sheet1의 A1:D10 범위를 반복하고, 절댓값이 0.01 미만인 숫자를 0으로 설정합니다.
예제 코드 - 1
Sub RoundToZero()
Dim rng As Range
For Each rng In Range("A1:D10")
If Abs(rng.value) < 0.01 Then rng.value = 0
Next
End Sub
다음 코드는 For Each 문을 사용하여 A1부터 A10까지의 셀 범위를 반복하고, 각 셀의 값을 출력합니다.
예제 코드 - 2
Sub LoopThroughCells()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
Dim cell As Range
For Each cell In ws.Range("A1:A10") ' A1부터 A10까지의 셀 범위 반복
Debug.Print cell.value ' 각 셀의 값을 출력
Next cell
End Sub
다음 코드는 마지막 데이터가 있는 행을 찾은 후, A1부터 해당 행까지의 셀 범위를 반복하면서 각 셀의 값을 2배로 증가시키고,짝수행만 셀의 배경색을 주황색으로 변경합니다.
예제 코드 - 3
Sub LoopThroughCells()
Dim ws As Worksheet
Dim cell As Range
Dim rowNum As Long
Dim lastRow As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row ' 데이터가 있는 마지막 행을 찾음
For Each cell In ws.Range("A1:A" & lastRow) ' A1부터 마지막 행까지의 셀 범위 반복
rowNum = cell.Row ' 현재 셀의 행 번호 가져오기
If rowNum Mod 2 = 0 Then ' 짝수행인 경우
cell.value = cell.value * 2 ' 각 셀의 값을 2배로 증가
cell.Interior.Color = RGB(255, 192, 0) ' 각 셀의 배경색을 주황색으로 변경
End If
Next cell
End Sub
Exit For
Exit For 문을 사용하여 For Each...Next 루프를 종료할 수 있습니다. 예를 들어, 오류가 발생하면 If...Then...Else 문 또는 특히 오류를 확인하는 Select Case 문의 True 문 블록에서 Exit For 문을 사용합니다. 오류가 발생하지 않으면 If…Then…Else 문은 False이고 루프는 예상대로 계속 실행됩니다.
다음 예제에서는 A1:B5 범위에서 숫자가 포함되지 않은 첫 번째 셀을 테스트합니다. 이러한 셀이 발견되면 메시지가 표시되고 Exit For가 루프를 종료합니다.
예제 코드 - 1
Sub TestForNumbers()
Dim rng As Range
For Each rng In Range("A1:B5")
If IsNumeric(rng.value) = False Then
MsgBox "Cell " & rng.Address & " contains a non-numeric value."
Exit For
End If
Next rng
End Sub
다음 코드에서는 A1부터 마지막 행까지의 셀 범위를 반복하면서 값이 5인 셀을 찾고, 해당 셀을 찾으면 루프를 종료합니다.
예제 코드 - 2
Sub ExitForExample()
Dim ws As Worksheet
Dim cell As Range
Dim lastRow As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row ' 데이터가 있는 마지막 행을 찾음
For Each cell In ws.Range("A1:A" & lastRow) ' A1부터 마지막 행까지의 셀 범위 반복
If cell.value = 5 Then
MsgBox "값이 5인 셀을 찾았습니다."
Exit For ' 값이 5인 셀을 찾으면 루프를 종료
Else
End If
Next cell
End Sub
다음 코드에서는 A1부터 A10까지의 셀 범위를 반복하면서 셀의 값에 따라서 특정 동작을 수행하고, 특정 조건을 만족하면 루프를 종료합니다.
예제 코드 - 3
Sub ForEachWithSelectCase()
Dim cell As Range
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
For Each cell In ws.Range("A1:A10") ' A1부터 A10까지의 셀 범위 반복
Select Case cell.value ' 셀의 값에 따라 분기
Case "Apple"
' 셀 값이 "Apple"인 경우, "Apple" 메시지 출력
MsgBox "Fruit: Apple"
Case "Banana"
' 셀 값이 "Banana"인 경우, "Banana" 메시지 출력
MsgBox "Fruit: Banana"
Case "Orange"
' 셀 값이 "Orange"인 경우, "Orange" 메시지 출력
MsgBox "Fruit: Orange"
Case Else
' 그 외의 경우, "Other" 메시지 출력 후 루프 종료
MsgBox "Other"
Exit For
End Select
Next cell
End Sub
For Each...Next 루프를 사용하여 VBA 클래스 반복
For Each...Next 루프는 컬렉션 객체의 배열과 인스턴스만을 반복하는 것이 아닙니다. For Each...Next 루프는 사용자가 작성한 VBA 클래스에 대해서도 반복할 수 있습니다.
다음은 이 작업을 수행하는 방법을 보여 주는 예제입니다.
1. VBE(Visual Basic Editor)에서 클래스 모듈을 만들고 이름을 CustomCollection으로 바꿉니다.
2. 새로 만든 모듈에 다음 코드를 배치합니다.
' CustomCollection 클래스
Private MyCollection As New Collection
' The Initialize event automatically gets triggered
' when instances of this class are created.
' It then triggers the execution of this procedure.
Private Sub Class_Initialize()
With MyCollection
.Add "First Item"
.Add "Second Item"
.Add "Third Item"
End With
End Sub
' Property Get procedure for the setting up of
' this class so that it works with 'For Each...'
' constructs.
Property Get NewEnum() As IUnknown
' Attribute NewEnum.VB_UserMemId = -4
Set NewEnum = MyCollection.[_NewEnum]
End Property
3. 이 모듈을 파일로 내보내고 로컬에 저장합니다.
4. 모듈을 내보낸 후 텍스트 편집기를 사용하여 내보낸 파일을 엽니다(Window의 메모장 소프트웨어로 충분합니다). 파일 내용은 다음과 같아야 합니다.
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "CustomCollection"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Private MyCollection As New Collection
' The Initialize event automatically gets triggered
' when instances of this class are created.
' It then triggers the execution of this procedure.
Private Sub Class_Initialize()
With MyCollection
.Add "First Item"
.Add "Second Item"
.Add "Third Item"
End With
End Sub
' Property Get procedure for the setting up of
' this class so that it works with 'For Each...'
' constructs.
Property Get NewEnum() As IUnknown
' Attribute NewEnum.VB_UserMemId = -4
Set NewEnum = MyCollection.[_NewEnum]
End Property
5. 텍스트 편집기를 사용하여 파일의 텍스트 아래 첫 번째 줄에서 문자를 제거합니다. 수정된 파일을 저장합니다. 'Property Get NewEnum() As IUnknown
--> ' Attribute NewEnum.VB_UserMemId = -4에서 주석을 제거하라는 뜻입니다.
Property Get NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
Set NewEnum = MyCollection.[_NewEnum]
End Property
6. VBE로 돌아가서 VBA 프로젝트에서 생성한 클래스를 제거하고 메시지가 표시될 때 내보내기를 선택하지 않습니다.
7. 문자를 제거한 파일을 VBE로 다시 가져옵니다.
8. 다음 코드를 실행하면 VBE와 텍스트 편집기를 모두 사용하여 작성한 사용자 지정 VBA 클래스를 반복할 수 있음을 확인할 수 있습니다.
Sub TestCustomCollectionIteration()
Dim Element
Dim MyCustomCollection As New CustomCollection
For Each Element In MyCustomCollection
MsgBox Element
Next Element
End Sub
편의상 MsgBox를 Debug.Print로 바꾸고 출력했습니다.
메모장이 아닌 클래스 모듈에서 주석을 제거하면 아래 그림과 같이 에러가 납니다.
메모장에서 주석을 제거하고 다시 불러오면 해당 부분이 숨겨진 상태가 됩니다.
Private MyCollection As New Collection
'개체의 인스턴스가 생성되면 'Initialize' 이벤트가 자동으로 트리거됩니다.
'그리고 이 이벤트가 실행되면 이 프로시저가 실행됩니다.
Private Sub Class_Initialize()
With MyCollection
.Add "First Item"
.Add "Second Item"
.Add "Third Item"
End With
End Sub
'이 클래스가 'For Each...' 구문과 함께 작동하도록 설정하기 위한 Property Get 프로시저입니다.
Property Get NewEnum() As IUnknown
Set NewEnum = MyCollection.[_NewEnum]
End Property
NewEnum 속성은 VBA에서 For Each...Next 루프로 사용자가 작성한 클래스의 컬렉션을 인식할 수 있도록 해주는 역할을 합니다.
VBA에서 For Each...Next 루프를 사용하여 컬렉션을 순회하려면 해당 컬렉션에 대한 인터페이스가 필요합니다. 이를 위해 클래스에 "NewEnum"이라는 특별한 속성을 정의하고, 이 속성이 컬렉션의 "_NewEnum" 속성을 참조하도록 합니다. 이렇게 함으로써 For Each...Next 루프가 해당 클래스의 컬렉션을 인식하고 순회할 수 있게 됩니다.
비고
For...Each 블록은 그룹에 하나 이상의 요소가 있는 경우에만 실행됩니다. 루프에 들어간 후, 루프 내의 모든 명령문이 그룹의 첫 번째 요소에 대해 실행됩니다. 그룹에 더 많은 요소가 있는 경우, 루프 내의 명령문은 각 요소에 대해 계속해서 실행됩니다. 그룹에 더 이상 요소가 없으면 루프를 종료하고 Next 문 다음에 오는 명령문으로 실행이 계속됩니다.
For 문 내에 원하는 수의 Exit For 문을 어디에나 배치할 수 있으며 루프를 종료하는 대체 방법으로 사용됩니다. 주로 조건을 평가한 후에 Exit For를 사용하여 제어를 바로 Next 문 다음에 오는 명령문으로 전달합니다.
For...Each...Next 루프를 중첩할 수 있습니다. 한 For...Each...Next 루프를 다른 For...Each...Next 루프 내에 배치할 수 있습니다. 하지만 각 루프의 요소는 고유해야 합니다.
참고
Next 문에서 요소(element)를 생략하면 element가 포함된 것으로 간주되어 실행이 계속됩니다. Next 문이 해당하는 For 문보다 먼저 나오는 경우 오류가 발생합니다.
사용자 정의 형식(user-defined type)의 배열과 함께 For...Each...Next 문을 사용할 수 없습니다. Variant 변수에 사용자 정의 형식을 포함할 수 없기 때문입니다.
도움말 출처
Using For Each...Next statements (VBA)
Office VBA reference topic
learn.microsoft.com
'언어 참조' 카테고리의 다른 글
With 문 (0) | 2023.08.05 |
---|---|
Do...Loop 문 (0) | 2023.08.05 |
For...Next 문 (0) | 2023.08.04 |
인수를 효율적으로 전달하기 (0) | 2023.08.04 |
매개변수 배열 이해 (0) | 2023.08.04 |