WHERE 함수의 속사정

저는 IDL을 처음 접하시는 분들에게 WHERE를 소개할 때,

OK = WHERE(조건문)

으로 소개합니다. 이렇게 하면 배열 중 조건에 부합하는 요소의 위치(WHERE)를 리턴값으로 준다고 말씀 드립니다. 거의 사실이죠. 당장은 느낌도 좋구요, 데이터베이스의 WHERE 문을 쓰는 기분으로 사용할 수 있기 때문에 저는 이렇게 설명을 드리는 방식을 선호했습니다.

다음과 같이 다섯개의 원(circle) 정보 중에 반경이 7보다 큰 원을 찾아내는 방법은 우리가 생각하는 것 그대로 간단합니다.

0번, 2번, 4번이 RADIUS가 7보다 큰 놈들이라는 결과입니다. 별 새로울 것은 없습니다.  그런데, IDL의 도움말에서 WHERE를 보면 설명하는 방식이 좀 다릅니다. 이렇게 되어 있어요.

 

Result = WHERE (Array_Expression)

Result (리턴값)은 배열(Array_Expression)에서 0이 아닌 곳들의 배열 번호들이 담긴 배열이 된다.

예로 보는 게 더 이해가 쉬울 것 같습니다. 결국 이렇다는 얘기예요.

배열에서 0이 아닌 부분 즉, 0번, 2번, 4번을 조사해서 알려 주는 것입니다. WHERE 함수의 효용이 고작 0이 아닌 곳들을 조사하는 것 뿐이라고요? 맞습니다. 그게 진실이죠.  WHERE 함수의 첫 인자로 조건문을 넣으면 된다는 제 설명은,  IDL의 문법적인 해석을 하자면 오해의 소지가 있습니다. 조건문(또는 IDL의 문장)을 인자로 받아들이는 그런 장치는 사실 IDL에 없습니다. 함수가 무슨 컴파일러도 아니구요. 다만 함수나 프로시저의 인자로 수식이 주어질 때, 이 수식이 먼저 계산되고, 그 결과가 함수나 프로시저의 인자로 넘어가기 때문에 다음과 같은 일이 가능했던 것입니다.

print 프로시저의 인자로 수식을 받는 것이 아니라, 사실은, 3*4가 먼저 계산되기 때문에 PRINT 문 입장에서는 print, 12 로 처리되는 상황일 뿐입니다. 마찬가지로, WHERE(radius gt 7) 이 가능한 이유는 radius gt 7 이 먼저 계산이 되고, 그 계산 결과가 WHERE 함수로 넘겨지기 때문에 그럴듯하게 WHERE 함수 안에 조건문이 들어가는 모양새를 보이는 것입니다.

즉, where(radius gt 7) 은 먼저 radius gt 7 이 계산되고(조건을 만족하는 위치는 1, 만족하지 않는 부분은 0), 그 다음에 사실상 where([1, 0, 1, 0, 1]) 이 수행되는 셈입니다.

0이 아닌 곳의 위치라고 했으므로, 쓰일 일이 많지는 않겠지만, 다음과 같이 해도 결과는 같습니다.

그러므로, 다음과 같이 쓰는 것은 괜히 조건연산문 한번을 더 수행하는, 시간만 더 소모되는 불필요한 과정인 거지요.

즉, 배열에서 0이냐, 아니냐만을 판단하는 WHERE라면, 배열 그 자체로 바로 검색이 됩니다. 조건문을 더 돌릴 필요가 없습니다.

사용자로부터 “WHERE의 조건문이 너무 복잡해져서 코드가 보기 불편하게 되었다. 개선안이 없겠는가?” 하는 질문을 받았고, 저의 WHERE 함수 설명 방식이 오해를 드릴 수 있다는 반성을 하게 되어 이 글을 쓰게 되었습니다. 해당 사용자께서는 조건 10개 정도의 교집합을 찾는 기능을 구현하고 있었습니다. 여기서는 예제니까, 두 개의 조건에 대한 교집합을 찾는 상황을 만들어 보겠습니다.

좌표 (3, 2)로부터의 거리가 1 미만이고, 반경은 3보다 큰 원을 찾는 조건입니다. 두 개 정도의 조건에 대한 AND 면 보기가 그리 불편하지는 않지만,  이런 조건이 AND / OR가 10개 정도로 이어지면 보기도 힘들고, 유지보수성이 떨어지는 것은 사실입니다.

도움말에 나오는 대로, WHERE 함수에는 최종 합격 여부(1 또는 0)만 전달되면 됩니다. 나머지는 다 밖으로 빼낼 수 있어요.

where 함수에는 최종 합격/불합격 목록 배열(final_cond) 만 넘겨주면 되는 거죠.

IDL 사용자들에게 매우 인기있는 함수, 어쩌면 함수 이상으로 여겨지고 있는 WHERE가 사실상 “0이 아닌 위치만 찾는 기능을 가질 뿐”이라는 진실은 약간 실망스러울 수도 있습니다. 하지만, 이 단순한 작업 역시 “WHERE 안쓰고 해결해 보라”는 상황이 되면 느리고 불편한 반복문을 돌려야 됩니다. 별 것 아닌 것 같지만, 사실 요긴한 기능을 가지고 있는 거지요. 다양한 상황에 사용될 수 있도록 잘 정제된 기능만 가지고 있는 것이라고, 저는 생각합니다.

WHERE(조건문) 형식으로 사용하시라고만 설명드리고 말았던 과거 행적을, 저는 기억하고 반성합니다.