(mapcar) and (lambda)

by Kenny Ramage (http://www.afralisp.net/autolisp/tutorials/mapcar-and-lambda.php)


당신도 알다시피, LISP은 "목록처리", 즉 당신이 목록을 만질 수 있게 하는 꽤 많은 함수가 있다.

이 중에서 첫번째로 항목에 함수를 적용 할 수 있도록 명령인 (mapcar)를 알아보자.

(mapcar)

이 기능은 각 각의 리스트에 기능을 부여할 수 있게 한다. 아래 단순한 예제가 있다.

리스트의 각 항목에 1을 더할 경우


	(setq a 1)
	(mapcar '1+ (list a))

이 예제는 2 를 반환한다.

이 과정은

mapcar 는  (list a) 의 각 항목에 1 을 더해서 2 를 만들어 낸다.

좀 더 긴 목록으로....


	(setq a '(1 2 3 4 5 6 7 8 9 10))
	(mapcar '1+ a)

이 것은 아래와 같은 값을 반환한다.


	(2 3 4 5 6 7 8 9 10 11)

Just a few words on creating lists in AutoLisp 은 매우 간단한 명령어로 목록을 만드는데...이 리스트를 만드는 두가지 방법이 있다. 첫번째는 (getpoint) 와 (entget) 처럼 목록을 생산하는 명령어를 이용하는 것이다. 이 두 명령어는 목록을 반환한다.


두번째는 (list) 를 이용하는 것이다. 예를 들어:


	(setq a (list 1 2 3 4 5))

변수 a 는 아래와 같은 값이다.


	(1 2 3 4 5)

다른 방법은 아래와 같이 표현되는 것이다.

	(setq a '(1 2 3 4 5))

두 방법은 모두 동일한 목록을 기록한다.


여기 다시 또 다른 방법인 (mapcar) 가 있다.


변수 arglist. 에 저장되는 목록이 있다.


(setq arglist '(12.0 145.8 67.2 "M20"))

당신이 목록의 각 각 내용을 역시 각기 다른 변수에 넣고 싶다면 아래와 같은 방법이 있다.


   (setq a (nth 0 arglist))
   (setq b (nth 1 arglist))
   (setq c (nth 2 arglist))
   (setq d (nth 3 arglist))

이 일은 작동하기는 하나, 매우 느리다. 이 경우 확실히 더 나은 방법은  MAPCAR 를 이용하는 것이다.


(mapcar 'set '(a b c d) arglist)

목록의 두번째 항목을 첫번째 항목의 변수로 각각 적용하는데 일반적인 SETQ 대신 SET 기능이 사용되었다.

만약 외부파일에서 목록을 읽는 다면, 문자열로 읽히게 된다. 예를 들어

목록이  아래와 같이 보여야 하는데...


	(10 20 30 40 50)

그러나, 파일로 부터 목록을 읽게 되면, 아래와 같이 보이게 된다.


	("10" "20" "30" "40" "50")

이 경우 (mapcar) 를 이용해서 쉽게 정수로 변환가능하다.


	(setq b (mapcar '(atoi) thelist)) 

이제 이 함수를 잘 이해했으리라 생각한다. 그러나, 이제 이 (mapcar) 를 이용해서 어떻게 기능과 엮는지를 익혀야 한다.

Radians로 변경을 원하는 각도들이 있다면...


 (setq c '(23.0 47.8 52.1 35.6))

먼저 이 들 사이를 변환시키는 명령어를 만들어야 한다.:


(defun dtr (a)

	(* pi (/ a 180.0))
)

그런 후 아래와 같이 변화시키면 된다.

	(setq d (mapcar 'dtr c))

만들어진 (dtr) 명령어는 c 목록의 각각의 요소에 적용되었다. 

이 기능은 아래와 같이 사용될 수 도 있다.


	(setq d (mapcar (quote dtr) c))

(lambda)

이제 (lambda) 를 알아보자.  (lambda) 는 위와 같은 경우 (dtr) 명령어를 만들지 않고, 같은 구문에서 (mapcar) 의 기능을 수행할 수 있게 한다.


	(setq d (mapcar (quote (lambda (a) (* pi (/ a 180.0)))) c))

또는

	(setq d (mapcar '(lambda (a) (* pi (/ a 180.0))) c))

이 기능은 각도들을 라디안으로 변경하게 하고, 변수 d 에 저장하게 한다.

(lambda) 기능을 잘게 쪼개서 살펴보자.


	(lambda (a) (* pi (/ a 180.0)))

는 아래와 같다.


	(defun (a) (* pi (/ a 180.0)))

아래 명령어를 실행해 보자.


(defun c:test ()
	(setq c '(23.0 47.8 52.1 35.6))
	(setq d (mapcar '(lambda (a) (* pi (/ a 180.0))) c))
	(mapcar 'set '(w x y z) d)
   (princ)
)

!c 는 (23.0 47.8 52.1 35.6)
!d 는 (0.401426 0.834267 0.909317 0.621337)
!w 는 0.401426
!x 는 0.834267
!y 는 0.909317
!z 는 0.621337

을 각각 반환한다.


AutoCad 사용자 설명서를 인용 :


"새로운 함수를 정의하고자 하지 않을 때 (람다) 함수를 사용한다. 또한 프로그래머의 의도가 보다 명확이 사용되고자 할 때 사용되기도 한다."

예를 들어 (lambda) 는 빠른 기능 역할을 하고 싶은 어디든 사용될 수 있고, 또한 새로운 (defun) 명령어를 탑재함으로써 발생되는 문제점을 해소하고 싶을 때도 사용할 수 있다.


위의 예제와 별도로 목록에 기능을 부여하는 AutoLisp 명령어로 (apply) 와 (foreach)가 있다. 이 것을 살펴보자.

(apply)

이 기능은  (mapcar) 와는 달리 목록 속의 전체 요소에 영향을 미친다. 두가지 예제가 있다.


	(apply '+ '(1 2 3))

이 예제는 6 을 반환한다..


	(apply 'strcat '("a" "b" "c"))

이 예제는 "abc" 를 반환한다.

(apply) 를 (lambda) 와 함께 사용할 수도 있다.


	(apply '(lambda (x y z)
		(* x (- y z))
		)
		'(5 20 14)
	)

이 것은 30을 반환한다. (20-14*5=30)

(foreach)

이 명령어는 다름과 같은 구성을 가져야 한다.: (foreach name list expression…)


이 기능은 목록의 요소들을 하나씩 꺼내서 사용하는 개념이다.


	(foreach n a (princ n) (terpri))

아래와 같은 목록에 적용한다면  :


	(setq a (1 2 3 4 5))

아래와 같은 결과를 반환한다.


	1
	2
	3
	4
	5


이제 이 것들을 사용해서 즐기는 것만 남았다.

---------------------------------------------------------------

(setq curlst '("a" "b" "c" "d"))
(setq delst '("a" "b"))

(vl-remove-if '(lambda (x) (car (member x delst))) curlst)

리턴은 ("c" "d")

---------------------------------------------------------------



 

'Lisp & Tips > Lisp' 카테고리의 다른 글

SSGET 사용법 정리  (0) 2014.11.07
리스트에서 순서 뽑기 기초  (0) 2014.10.27
Entmake 할 때, 객체별 요구리스트 정리  (0) 2014.10.25
켜 생성  (0) 2014.10.11
소실된 SHX 파일 퍼지  (0) 2014.09.08