2014-03-24 116 views
1

我是新來的lisp,我試圖交換數組中的兩個元素。我想知道是否有函數獲取指定的位置,所以我可以使用rotatef來交換它們。Lisp數組元素交換

我試過函數的位置,但它不適用於數組,因爲它不是一個序列。

如果沒有數組的內置函數,什麼是最好的計算解決方案?

我周圍搜索,似乎無法找到一個簡單的解決方案。行是主要的解決方案嗎?

基本上,我想找到的元素的2維陣列中的位置,並返回所述位置在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) 

當然,您不需要將位置綁定到名稱。這將工作太:

(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) 

如果問題是position沒有找到您所需要的元素,它的:test參數可能會有所幫助。還有position-ifposition-if-not函數可讓您提供自己的謂詞以識別元素。在HyperSpec中,所有三個都被描述爲here

這裏有一個可能不會與:test論點沒有論據:test工作,因爲默認值(eql所有序列功能的例子 - 見表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上測試)。

補充:

這裏有一個蠻力方式與二維數組來做到這一點。 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),當我嘗試位置時它說它是一個非序列 我應該收到一個2維NxN數組和數字,並且想要發現零。在你的最後一個例子中,位置的作用是因爲你搜索的是一個列表,而不是列表中的數字,而不是2。在前兩個例子中,它們都是被認爲是序列並因此定位的矢量,但是如果它是2維的sional array lisp認爲它是非序列的 – d0pe

+0

的確,這是真的。我沒有意識到你正在使用一個二維數組。你可能想要更明確地將它添加到你的問題中(雖然Rainer似乎已經理解了,所以也許它只是我!) – jbm

+0

@ d0pe,我添加了一個蠻力方法,可以在二維數組上工作(類似於你考慮到你對Rainer的評論,我認爲)。我沒有機會在CL中使用多維數組,所以可能有更好的方法 - 我建議繼續研究Rainer的建議。 – jbm

3

要使用可以使一維移位陣列和使用,作爲用於position矢量。

例子:

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上使用,但似乎不合邏輯。 此外,我如何從一維數組回到兩個維度? 無法循環訪問數組,並在找到nil時返回?我試着用(循環爲我從0到N做(循環從J從0到N do)(當(數組ij)無)(返回(列表ij))))但似乎不工作 – d0pe

+0

@ d0pe:確定你可以很容易地交換它們,使用rotatef來移動它們,並且你不需要返回任何東西,位移的數組是一個新的數組,它引用原始數組。 –