2014-03-24 3 views
1

저는 Lisp에 익숙하지 않아 배열에서 두 요소를 교환하려고합니다. rotf를 사용하여 스왑 할 수 있도록 지정된 위치를 가져 오는 함수가 있는지 알고 싶습니다.Lisp 배열 요소 스왑

함수 위치를 시도했지만 시퀀스가 ​​아니기 때문에 배열에서 작동하지 않습니다.

어레이의 기본 제공 함수가없는 경우 최상의 계산 솔루션은 무엇입니까?

나는 주위를 둘러 보았고 간단한 해결책을 찾지 못하는 것 같습니다. 로우 메이저가 해결책입니까?

는 기본적 네가 일차원 변위 배열하고 position위한 벡터로서 것을 사용할 수 rotatef

답변

1

내가이 일을해야한다고 생각 - 배열이 참 시퀀스입니다.

(let* ((an-array (make-array 6 :initial-contents '(#\f #\o #\o #\b #\a #\r))) 
     (f-pos (position #\f an-array)) 
     (r-pos (position #\r an-array))) 
    (rotatef (elt an-array f-pos) 
      (elt an-array r-pos)) 
    an-array) 
;=> #(#\r #\o #\o #\b #\a #\f) 

물론 위치를 이름에 바인딩 할 필요는 없습니다. 이 역시 작동합니다 : 문제가 position는 당신이 필요로하는 요소를 찾지 못하는 함께

(let ((an-array (make-array 6 :initial-contents '(#\f #\o #\o #\b #\a #\r)))) 
    (rotatef (elt an-array (position #\f an-array)) 
      (elt an-array (position #\r an-array))) 
    an-array) 
;=> #(#\r #\o #\o #\b #\a #\f) 

경우, 그 :test 인수는 도움이 될 수 있습니다. 또한 요소를 식별하기위한 자체 술어를 제공 할 수있는 position-ifposition-if-not 함수가 있습니다. 세 가지 모두 HyperSpec에 here으로 설명되어 있습니다. 여기

아마 :test 인수와 함께 모든 시퀀스 기능 eql 인 (기본 때문에, :test 인수없이 작동하지 않습니다 예입니다 - 표준 시퀀스 기능 키워드 인수의 좋은 요약 테이블 11-2 here 참조) 목록에 작동하지 않습니다.

(let ((an-array (make-array 3 :initial-contents '((1 2 3) 
                (4 5 6) 
                (7 8 9))))) 
    (rotatef (elt an-array (position '(1 2 3) an-array :test #'equal)) 
      (elt an-array (position '(7 8 9) an-array :test #'equal))) 
    an-array) 
;=> ((7 8 9) (4 5 6) (1 2 3)) 

(SBCL 1.0.55.0.debian에서 테스트 됨).

추가 :

는 여기에 2 차원 배열로 할 수있는 무력 방법입니다. find-position은 배열의 크기가 (3 3)이라고 가정하지만 약간 더 일반적으로 만들 수 있습니다.

내가 최고의 솔루션이를 옹호하지 않습니다,하지만 난 당신의 질문을 :) 오해 후에 당신에게 빈손를 마칠 수있었습니다

(defvar an-array #2A((1 2 3) (4 5 6) (7 8 9))) 

(defun find-position (array item &key (test #'eql)) 
    (loop for i below 3 do 
     (loop for j below 3 do 
       (when (funcall test (aref array i j) item) 
       (return-from find-position (list i j)))))) 

(defun swap-4-and-7 (array) 
    ;; Example use 
    (destructuring-bind (i1 j1) (find-position array 4) 
    (destructuring-bind (i2 j2) (find-position array 7) 
     (rotatef (aref array i1 j1) 
       (aref array i2 j2)))) 
    array) 

(swap-4-and-7 an-array) 
;=> #2A((1 2 3) (7 5 6) (4 8 9)) 
+0

make-array '(3 3)와 make-array 3의 차이점은 무엇입니까? make-array'(3 3)를 통과 했으므로 위치를 시도 할 때 시퀀스가 ​​아닌 것을 말합니다 숫자와 nil을 가진 2 차원 NxN 배열을 받고 nil을 찾고 싶습니다. 마지막 예제에서 위치는 2와 같이 목록 안의 숫자가 아닌 목록을 검색하기 때문에 작동합니다. 그리고 처음 두 예제에서 두 시퀀스는 시퀀스로 간주되어 위치 연산을하는 벡터입니다. 그러나 2 차원이면 synt array lisp는 그것이 비 시퀀스라고 생각한다 – d0pe

+0

실제로, 사실이다. 당신이 2 차원 배열로 작업하고 있다는 것을 깨닫지 못했습니다. 질문에 좀 더 명시 적으로 추가하고 싶을 수도 있습니다. Rainer가 이해 한 것처럼 보일 수도 있습니다. – jbm

+0

@ d0pe, 2 차원 배열에서 작동하는 무차별 대입 방식을 추가했습니다. Rainer에 대한 당신의 의견에 생각했습니다.) CL에서 다차원 배열로 작업 할 기회가 없었으므로 더 나은 방법이 될 수 있습니다. Rainer의 제안을 계속 살펴볼 것을 권합니다. – jbm

3

에서 사용되는 2 차원 배열의 요소의 위치를 ​​찾을 위치를 반환 할 .

예 :

CL-USER 9 > (let ((a0 (make-array '(2 3) 
            :initial-contents '((foo1 bar foo2) 
                 (foo3 baz foo4))))) 
       (let ((a1 (make-array (reduce #'+ (array-dimensions a0)) 
            :displaced-to a0))) 
       (let ((pos1 (position 'baz a1)) 
         (pos2 (position 'bar a1))) 
        (when (and pos1 pos2) 
        (rotatef (aref a1 pos1) 
          (aref a1 pos2))))) 
       a0) 
#2A((FOO1 BAZ FOO2) (FOO3 BAR FOO4)) 
+0

헤이 라이너, 팁을위한 감사합니다. 이 작동하지만 지금은 효율적으로 그들을 바꿀 수 없습니다. 항상 rotatef에서 사용할 배열 좌표로 위치를 바꿀 수는 있지만 논리적으로 보이지는 않습니다. 또한 1 차원 배열을 2 차원으로 되돌리려면 어떻게해야합니까? 배열을 순환하여 nil을 찾았습니까?나는 0에서 N까지의 루프를 시도했다. 0에서 N까지의 j에 대한 루프는 (eq (aref-array ij) nil) (return (list ij))))) 그러나 작동하지 않는다. – d0pe

+0

@ d0pe : rotatef를 사용하여 치환 된 배열을 사용하여 교체 할 수 있습니다. 또한 되돌릴 필요가 없습니다. 대체 된 배열은 원래 배열을 참조하는 새로운 배열입니다. –