2013-08-13 2 views
2

CL로 새로 워서 간단한 알고리즘으로 많은 것을 할 수 있습니다. 예를 들어, 목록의 모든 고유 요소를 제거하는 함수를 구현하려고했습니다. 이 코드에Common Lisp에서 문자열과 숫자의 핵심 차이점은 무엇입니까?

(1 2 2 3 3 4 5 3) -> (2 2 3 3 3)

첫 번째 시도 리드 :

(defun remove-unique (items) 
    (let ((duplicates (set-difference items (remove-duplicates items :test #'equal)))) 
    (append duplicates (remove-duplicates duplicates :test #'equal)))) 

이 문자열 확인을 작동하지만 항상 숫자 NIL를 반환 않습니다. set-difference에 대해 조금 더 읽기 저는 중복 된 채워진리스트를 가지고 일하는 것이 아니라는 것을 배웠습니다. 제 경우에는 어떻게 든 작동합니다. 그래서 나는 이식 할 수없는 방식을 포기하고 함께 움직였습니다.

또 다른 시도는 다음과 같습니다

(defun remove-unique (items) 
    (loop for item in items 
    when (member item (cdr (member item items))) 
    collect item)) 

을 그리고이 숫자로 확인 작동하지만 문자열을 NIL 반환합니다.

분명히 이해할 수없는 문자열과 숫자의 핵심 차이점이 있습니다. memberset-difference과 같은 목록 처리 기능이 어떻게 다르게 작동합니까?

+1

'member'도 목록 항목에 적용 할 비교의 종류를 지정하는 술어를 취합니다. –

+0

감사! 나는 그것에 대해 정말로 잊었다. 그러나 문자열의 경우 여전히 'NIL'입니다. – akalenuk

+0

실제로'test'가 누락되었습니다. 두 번째 테스트를 할 때 중복이없는 목록을 입력했습니다 .--) 그것이 나에게 전혀주지 않은 것은 당연합니다. – akalenuk

답변

1

문자열 숫자에 비해 목록에 더 많은 관련이 있습니다.

"Hello"

는 시퀀스 (compund 데이터 형식) 프리미티브 값 #\H 문자로 시작하고 끝나는 #\o이다.

'(1 2 3)

는 시퀀스 (compond 데이터 형식) 프리미티브 숫자 값 1에서 시작하여 3

문자로 끝나는들이 프리미티브 값 인 것을 숫자 비슷하다. 같은 객체없는 시퀀스는, 일반적으로 뭔가를 비교하는 옵션라는 이름의 인수를 가지 커먼 리스프에 equal

(setq list1 (list 1 2 3)) 
(setq list2 (list 1 2 3)) 

(eql list1 list2) 
;==> NIL 

(equal list1 list2) 
;==> T 

;; comparing first element of both lists using eql 
(eql (car list1) (car list2)) 
;==> T 

(setq string1 "Hello") 
(setq string2 "Hello") 

(eql string1 string2) 
;==> NIL 

(equal string1 string2) 
;==> T 

;; comparing first character of both strings using eql 
(eql (elt string1 0) (elt string2 0)) 
;==> T 

(모든 경우) 대부분의 함수를 사용하여 비교 될 수있는 반면 원시 값은 eql를 사용하여 비교 될 수 :test 곳 요소를 비교하는 방법을 제공 할 수 있습니다. 기본값은 보통 eql입니다. 이들이 시퀀스와 정확히 일치하도록하려면 #'equal:test으로 입력해야합니다.

1
(defun remove-unique (items &key (test 'eql)) 
    (loop 
    :with table := (make-hash-table :test test) 
    :for element :in items :do 
    (setf (gethash element table) 
      (1+ (gethash element table 0))) 
    :finally 
    (return 
     (loop 
      :for k :being :the :hash-keys :of table 
      :using (:hash-value v) 
      :when (> v 1) :nconc (make-list v :initial-element k))))) 

(defun remove-unique (items &key (test 'eql)) 
    (loop 
    :with table := (make-hash-table :test test) 
    :for element :in items :do 
    (setf (gethash element table) 
      (1+ (gethash element table 0))) 
    :finally 
    (return 
     (loop 
      :for element :in items 
      :unless (= 1 (gethash element table)) 
      :collect element)))) 

해시 테이블에서 읽는 횟수가 적기 때문에 아마 첫 번째 변형을 사용 하겠지만 목록의 항목이 나중에 수정되지 않았는지 확인해야합니다.

(remove-unique '("1" "2" "2" "3" "3" "4" "5" "3") :test #'equal) 

을 제공합니다

("2" "2" "3" "3" "3") 

하지만

(remove-unique '("1" "2" "2" "3" "3" "4" "5" "3")) 

준다 : 두 목록 및 문자열 시퀀스 때문에

NIL 
2

숫자, 문자 및 문자열의 동일성 비교는 실제로 다릅니다.더 비싸기 때문에 사용하는 것을 조심해야하는 Equal은 구조 평등을 만듭니다 (따라서 일부 객체에서 강등됩니다). eq는 객체 평등을 수행합니다. 그리고 EQL는 (그들은 '값을'확인) 대부분 (그들이 유형과 값을 확인) 번호를 제외한 경우와 문자에 대한 평등을 반대하지

equal, eql 및 자세한 내용은 eq에 대한 HyperSpec과 항목을 참조하십시오.

관련 문제