Lisp数组元素交换

时间:2014-03-24 20:26:27

标签: arrays position lisp

我是lisp的新手,我试图在数组中交换两个元素。我想知道是否有一个函数来获取指定的位置,所以我可以使用rotatef来交换它们。

我已尝试过功能位置,但它不适用于数组,因为它不是一个序列。

如果没有针对数组的内置函数,最佳计算解决方案是什么?

我已经四处搜索,似乎无法找到一个简单的解决方案。行主要是解决方案吗?

基本上,我想在二维数组中找到一个元素的位置并返回在rotatef中使用的位置

2 个答案:

答案 0 :(得分: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))

答案 1 :(得分: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))