VB(A)/당근쨈 & Chronicle

[& Chronicle] 중복값 제거 & 중복값의 개수

당근쨈 2017. 5. 2. 09:05

당근쨈 VS Chronicle

같은 주제로 매크로와 수식의 풀이과정을 살펴보는 새로운 도전입니다.
여기서 VS란 경쟁이 아닌 생각의 차이, 즉 접근방식에 따른(매크로 or 수식) 생각하는 과정을 이야기합니다.
해외 사례인 Mr Excel & ExcelisFun 을 보고 이 내용을 착안해내신
씽크탱크 Chronicle님의 아이디어에 감탄합니다.

먼저 카페에 올라온 질문글입니다.
http://cafe.naver.com/excelmaster/117697

1. 명단의 중복값을 제거하고
2. 명단의 개수를 나타낸다

가 이 질문의 핵심입니다. 아래는 Chronicle님의 수식입니다.
=INDIRECT(TEXT(MIN(IF(($C$2:$J$31<>"")*(COUNTIF($B$33:B33,$C$2:$J$31)=0),ROW($2:$31)*100+COLUMN($C:$J),7^8)),"R0C00"),)&""
cs

수식에 까막눈인 저로서는 아무리 봐도 감조차 오질 않습니다.
자세한 수식풀이과정은 http://blog.naver.com/asaph16/220540693438 를 참고하시기 바랍니다.(감탄)

다음은 제가 풀이한 매크로입니다.
코드를 보면 복잡해보이나 Collection으로 중복값을 제외하는 내용을 제외하면 아무 내용이 없습니다.
웬만하면 매크로보다는 수식으로 해결하는 것이 여러모로 낫지만
특히 배열수식의 경우는 데이터가 많아지면 엑셀이 극도로 느려지는 문제가 있고
한 글자만 실수로 지워도 수식이 틀어지는 우려가 있으니
속도면에서 보나 안전측면에서 보나 매크로를 저는 애용하고 있습니다.

한땀한땀 주석을 달아놨으니 해석에는 무리가 없으리라 봅니다.

Option Base 1   '배열을 1부터 시작하게 합니다.
Option Explicit '변수가 선언되지 않으면 에러를 표시합니다.
 
Sub Macro()
 
    Dim DataRange As Range  '급식제외자 영역
    Dim SingleRange As Range    '순환문에 쓰일 변수
    Dim C As New Collection '급식제외자 중복제거용 Collection
    Dim i As Long   '중복제거된 급식제외자를 순환할 변수
    Dim NoEat() As Variant  '급식제외자 명단, 급식제외일수, 총급식일 등 담을 배열
    
    Set DataRange = Range("C2:J31"'급식제외자 영역 설정
    
    On Error Resume Next    '급식제외자가 또 나오면 에러남. 에러방지
    
    '급식제외자 영역에서 데이터가 있는 영역만 순환하면서 중복값 제거하여 Collection에 담기
    For Each SingleRange In DataRange.SpecialCells(2)
        C.Add SingleRange, CStr(SingleRange)
    Next SingleRange
    
    On Error GoTo 0
    
    ReDim NoEat(C.Count, 6'중복값 제거된 급식제외자 수만큼 재배열
    
    '셀에 출력할 내용을 배열에 담음
    For i = 1 To C.Count
        NoEat(i, 1= i '순번
        NoEat(i, 2= C.Item(i) '급식제외자 이름
        NoEat(i, 3= WorksheetFunction.CountIf(DataRange, NoEat(i, 2)) '급식제외일수
        NoEat(i, 4= 22    '총 급식일수
        NoEat(i, 5= NoEat(i, 4- NoEat(i, 3'실 급식일
        NoEat(i, 6= NoEat(i, 5* 3900    '급식비
    Next i
    
    Range("A34").Resize(C.Count, 6= NoEat '셀에 출력
    
End Sub
cs

급식제외자.xlsm