엑셀 VBA에서 중복을 제외한 숫자 계산

9086 단어 ExcelVBA

소개



엑셀로 중복을 제외한 아이템의 개수를 세고 싶을 때가 상당히 있습니다.
연상 배열(딕셔너리)을 사용해 세는 방법이 잘 소개되고 있습니다만, 이번 좀 더 복잡한 상황에 조우했으므로 투고합니다.

구체적으로는 이런 상황입니다.


즉, 1개의 셀에 ccc/aaa와 같이 복수의 아이템을 "/"로 단락지어 있고, 이것을 「ccc」와 「aaa」와 구별한 후에 중복되어 있지 않은 아이템의 개수를 세고 싶다고 한다 상황입니다.

코드



함수로 정의합니다. 인수로 셀 범위를 지정하고 정수를 반환합니다.

흐름으로서는
1. 연관 배열 dict 만들기
2. 인수의 셀 범위의 각 셀에 대해 루프 처리를 실행(3~4)
3. 셀의 값이 dict의 키에 존재하는 경우, 다음 셀로
4. 셀이 빈 셀이 아닌 경우, dict 키에 셀의 값을, 값에 1을 추가
5. 다음으로, dict의 각 키에 대한 루프 처리를 실행(6~)
6. 키에 "/"가 포함되어 있으면, 그 키를 "/"로 분리해 다른 변수 splitTxt에 배열로서 격납해, 이 키 자체는 dict로부터 삭제
7. splitTxt에서 루프 처리 실행(8~9)
8. 분리 된 문자열 txt가 dict의 키에 존재하면 다음 txt로
9. 그렇지 않으면 txt를 dict 키에 추가하고 값은 1입니다.
10. countNumber의 반환 값으로 dict의 요소 수를 반환합니다.
Function countNumber(rng As Range) As Long

Dim dict As Object

Dim x As Range
Dim keyTxt As String
Dim key, splitTxt, txt As Variant

Set dict = CreateObject("Scripting.Dictionary")

For Each x In rng
    If dict.exists(x.Value) Then
        GoTo continue1
    End If

    If Not IsEmpty(x) Then
        dict.Add x.Value, 1
    End If
continue1:
Next


For Each key In dict
    If key Like "*/*" Then
        keyTxt = key
        splitTxt = Split(keyTxt, "/")
        dict.Remove key

        For Each txt In splitTxt
            If dict.exists(txt) Then
                GoTo continue2
            Else
                dict.Add txt, 1
            End If
continue2:
        Next
    End If
Next

countNumber = dict.Count

End Function

간단히 설명



먼저 VBA에서 연관 배열을 사용하는 경우 변수를 개체로 선언하고 CreateObject 함수를 사용해야 합니다.
Dim dict As Object

Set dict = CreateObject("Scripting.Dictionary")

그런 다음 연관 배열의 키에 각 셀의 값을 넣습니다. 키에 대한 값은 뭐든지 좋기 때문에 1로 했습니다.
이제 인수의 셀 범위에 있는 각 셀에 대해 처리를 수행하기 위해 For Each 문을 사용합니다. 첫 번째 If 문은 "연상 배열 dict에 이미 키가 존재하는 경우 continue1까지 가라."라는 처리입니다. 일반적인 프로그래밍 언어에서는, continue문이라고 하는 것이 있습니다만(루프를 1회 스킵 한다), VBA에는 없기 때문에, 이런 처리로 합니다.
두 번째 If 문은 셀이 빈 셀이 아닌 경우 dict 키에 셀의 값을, 값에 1을 추가하는 처리입니다.
이제 셀 값을 중복하지 않고 dict 키에 추가 할 수있었습니다 (원래 연관 배열은 키를 중복 할 수 없습니다 => 중복하려고하면 오류가 발생합니다).
For Each x In rng
    If dict.exists(x.Value) Then
        GoTo continue1
    End If

    If Not IsEmpty(x) Then
        dict.Add x.Value, 1
    End If
continue1:
Next

여기에서 이번 중요한 부분입니다.
dict중의 각 키에 대해서 루프 처리를 실시합니다. 키가 "/"를 포함하면 다른 문자열 변수 keyTxt에 저장됩니다. 그런 다음 Split 함수를 사용하여 "/"로 구분 된 문자열을 요소로 사용하는 배열을 splitTxt에 저장합니다. 이 키는 필요 없기 때문에 삭제합니다.

(참고 사이트) Split 함수 사용법 : Split 함수로 문자열 구분

그런 다음 splitTxt 배열에서 루프 처리를 수행합니다. 배열내의 각 요소가 dict 의 요소로서 존재하고 있으면, 루프를 스킵 해 (전과 같이), 그렇지 않은 경우 키로서 더합니다. 이제 dict의 키에는 중복이 없는 아이템이 갖추어진 것입니다.

For Each key In dict
    If key Like "*/*" Then
        keyTxt = key
        splitTxt = Split(keyTxt, "/")
        dict.Remove key

        For Each txt In splitTxt
            If dict.exists(txt) Then
                GoTo continue2
            Else
                dict.Add txt, 1
            End If
continue2:
        Next
    End If
Next

좋은 웹페이지 즐겨찾기