IDL/배열 생성 및 처리

UNIQ 함수에 관하여

이상우_idl 2018. 7. 23. 20:14
728x90
반응형

IDL에서 배열을 처리하는 내장함수들 중에 UNIQ라는 함수가 있습니다. 이 UNIQ 함수는 이름에서 짐작할 수 있듯이 unique라는 단어가 그 어원이라고 볼 수 있는데, 말 그대로 어떤 배열 내에서 unique한 값들만 골라내는 역할을 합니다. 좀 더 풀어서 얘기하면, 독립적이고 배타적인 값들만을 골라내는 기능을 합니다. 따라서 어떤 배열 내에 중복되는 값들이 다수 있을 경우, 중복되지 않는 서로 배타적이고 독립적인 값들만 추출해야하는 경우에 적합합니다. 예를 들어 다음과 같은 배열이 있다고 합시다.


data = [1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 5, 5]


보시다시피 data라는 배열은 총 12개의 값들을 갖고 있는데, 서로 중복되는 값들이 꽤 있습니다. 이 때 data 배열에 대하여 다음과 같이 UNIQ 함수를 적용시키고 그 결과를 출력해봅시다.


uq = UNIQ(data)

PRINT, uq


그러면 일단 다음과 같은 값들이 출력됩니다. 이 값들의 의미는 무엇일까요?


           2           4           8           9          11


이 값들은 모두 배열 인덱스입니다. 즉 data 배열에 있는 12개의 값들 중 인덱스가 2, 4, 8, 9, 11인 값들을 뜻합니다. 즉 3번째, 5번째, 9번째, 10번째, 12번째 값들을 뜻합니다. 그 값들을 아래에서 볼드체로 표시해보았습니다.


data = [111223333455]


결국 UNIQ 함수가 대상 배열에 대하여 그 안에서 중복되는 값들을 구분하는 마디에 해당되는 위치에 대한 인덱스들이라고 보면 됩니다.그리고 UNIQ 함수가 돌려준 결과 배열인 uq를 다음과 같이 원래 배열인 data에 대한 인덱싱에 이용할 수 있습니다.


PRINT, data[uq]


이렇게 출력된 결과는 다음과 같습니다.


       1       2       3       4       5


결국 원래 배열인 data에서는 1, 2, 3, 4, 5 각각이 여러개씩 중복되어 포함되어 있지만, UNIQ 함수를 사용하면 서로 중복되지 않는 최소한의 독립적인 값들만 골라낼 수 있음을 확인할 수 있습니다. 그런데 이번에는 data가 다음과 같은 형태일 경우를 가정해봅시다.


data = [5, 5, 4, 3, 3, 3, 3, 2, 2, 1, 1, 1]


이러한 경우에 대하여 아까와 같이 UNIQ 함수를 적용하여 바로 최종적인 결과를 얻을 수 있습니다. 편의상 중간 단계에서 uq의 값들을 출력하는 과정은 생략하였습니다.


uq = UNIQ(data)

PRINT, data[uq]


이렇게 하여 출력된 최종 결과는 다음과 같습니다.


       5       4       3       2       1


앞선 예제와는 값들의 순서가 다름을 확인할 수 있습니다. 사실은 UNIQ 함수는 그냥 사용하면 대상 배열상의 값들의 순서를 보존하는 방식으로 작동합니다. 중복되지 않는 독립적인 값들을 추출하면서도, 원본 배열 내에서의 순서를 따라가면서 골라낸다는 얘기입니다. 이러한 특성 때문에 예기치 않은 혼란이 올 경우도 있습니다. 만약 대상 배열인 data가 다음과 같을 경우를 봅시다.


data = [5, 5, 4, 3, 3, 3, 3, 2, 2, 1, 1, 1, 4, 4]


이 경우는 4라는 값이 앞쪽에 한번 등장했다가 뒷부분에서 재등장하는 경우입니다. 위와 똑같은 방식으로 UNIQ 함수를 적용하여 그 최종 결과를 출력해보면 다음과 같습니다.


       5       4       3       2       1       4


보시다시피 4가 두번 등장합니다. 분명히 중복되지 않는 독립적인 값들만 추출하고자 했으나, 그것이 실패한 상황입니다. 그 이유는 앞서 언급했던 것처럼 UNIQ 함수는 기본적으로는 원본 배열 내에서의 값들의 순서를 그대로 따라가면서 독립적인 값들을 선별하는 방식으로 작업을 수행하기 때문입니다. 따라서 위와 같은 사용 방식으로는, 중복이 일단 끝난 후 다시 재등장하는 값이 있을 경우에 대하여 제대로 대처하기가 어렵습니다.


사실 IDL 도움말에서 UNIQ 함수에 관한 내용을 찾아보면 설명이 이미 되어 있는데, UNIQ 함수는 원래는 대상 배열 내의 원소값들이 단조(monotonic) 증가 또는 감소하는 순서로 정렬된 상태에서 제대로 효과를 발휘합니다. 그러므로 만약 대상 배열 내 원소들이 크기 순서가 뒤죽박죽인 경우에는 일단 단조 증가 또는 감소하는 형태로 정렬(Sorting)을 다시 해준 다음에 UNIQ 함수에 투입하는 것이 바람직합니다. 따라서 중간에 SORT 함수를 한번 사용해주는 것도 방법일 수 있겠지만, 그냥 UNIQ 함수를 사용할 때 다음과 같이 SORT 함수를 함께 사용하는 것이 약간 더 간편합니다.


uq = UNIQ(data, SORT(data))

PRINT, data[uq]


이렇게 하면 최종 결과로 출력되는 값들은 다음과 같습니다.


       1       2       3       4       5


이와 같이 원래 배열 내에서 값들의 순서가 뒤죽박죽이어도 이렇게 하면 서로 완벽하게 독립적인 값들을 온전히 추출하는 것이 가능합니다. 다음과 같이 다양한 값들이 중복도 되고 순서도 뒤섞이는 등의 특징을 갖고 있을 경우가 실전에서는 더 많을 것입니다.


data = [14, 23, 13, 17, 22, 12, 23, 30, 13, 15, 18, 16, 27, 22]


이런 경우라 하더라도 방금 소개해드린 방법을 사용하면 서로 독립적인 값들만 정확히 추출할 수 있습니다.


      12     13     14     15     16     17     18     22     23     27     30



만약 오름차순이 아닌 내림차순으로 작업을 하고자 한다면, 다음과 같이 SORT의 결과를 REVERSE로 한번 더 감싸면 됩니다.


uq = UNIQ(data, REVERSE(SORT(data)))

PRINT, data[uq]


      12     13     14     15     16     17     18     22     23     27     30


배열 내 원소값들이 숫자가 아닌 문자일 경우에도 마찬가지입니다. 다음과 같이 문자값들로 구성되어 있을 경우에 대하여 똑같은 방법을적용하면 그 결과는 다음과 같습니다.


data = ['D', 'A', 'F', 'A', 'B', 'B', 'A', 'C', 'C', 'B']

uq = UNIQ(data, SORT(data))

PRINT, data[uq]


A B C D F


당연한 얘기이겠지만 이러한 방법은 배열이 1차원일 경우 뿐 아니라 2차원, 3차원 등등일 경우에도 동일한 방식으로 적용이 가능합니다.이 점도 함께 염두에 두시면 좋을 것 같습니다.

반응형