在Common Lisp中通过引用(而不是值)传递子数组

Dan*_*uko 3 arrays common-lisp pass-by-reference multidimensional-array pass-by-pointer

让我们假设我有一个数组 - 我将调用*my-array*- 看起来像这样:

#2A((1 2 3)
    (4 5 6)
    (7 8 9))
Run Code Online (Sandbox Code Playgroud)

我希望在子阵列上应用一些函数f

#2A((5 6)
    (8 9))
Run Code Online (Sandbox Code Playgroud)

我很乐意写作

(f (subarray *my-array* '(1 2) '(1 2))
Run Code Online (Sandbox Code Playgroud)

这里subarray需要作为参数:

  • 原始数组
  • 一个2元素的列表,在第一维上有起点和终点
  • 另一个2元素列表,第二维上有起点和终点
  • 等等

我正在寻找一些方法来通过f 引用(或通过指针?)而不是通过值将子数组作为参数传递给函数.

(解决这个问题的愚蠢方法是编写一个函数,在这个特定的情况下创建一个2*2数组并循环i和j复制原始数组中的值.但是,如果你处理相对较大的数组,这个会很贵.)

我发现存在一个cl-slice包但我不知道它是通过引用复制值还是访问数据.

sds*_*sds 6

Common Lisp有偏移数组,这正是你所要求的(参见array-displacement&c).

但是,在您的情况下,替换数组没有帮助,因为:

多维数组以行主顺序存储它们的组件; 也就是说,内部多维数组存储为一维数组,多维索引集按字典顺序排列,最后一个索引变化最快.

这意味着您的子数组不是主数组的连续部分,因此,您无法创建替换它的另一个数组.

PS.如果你无法弄清楚cl-slice是如何工作的,你可以用它time来查看它使用了多少内存并从中做出推断.

PPS.事实上,鞭打你想要的东西并不是很难:

(defmacro slice (array &rest ranges)
  "Return an accessor into ARRAY randing in RANGES."
  (let ((args (loop for r in ranges collect (gensym "SLICE-ARG-")))
        (arr (gensym "SLICE-ARRAY-")))
    `(let ((,arr ,array))
       (lambda ,args
         (aref ,arr
               ,@(loop for arg in args and (lo hi) in ranges
                   for range = (- hi lo)
                   collect
                     `(progn
                        (unless (<= 0 ,arg ,range)
                          (error "~S is out of range [0;~S]" ,arg ,range))
                        (+ ,lo ,arg))))))))

(defparameter *my-array*
  #2A((1 2 3)
      (4 5 6)
      (7 8 9)))

(defparameter f (slice *my-array* (1 2) (1 2)))

(loop for i from 0 to 1 do
    (loop for j from 0 to 1 do
        (format t " ~S" (funcall f i j)))
    (terpri))
 5 6
 8 9
Run Code Online (Sandbox Code Playgroud)