How do you copy an array in common lisp?

后端 未结 4 1446
温柔的废话
温柔的废话 2020-12-18 23:30

I\'d like to make copies of my 2D array, which feels like the nice, functional, nondestructive way of handling arrays. What is the lispy way of doing this?

相关标签:
4条回答
  • 2020-12-18 23:43

    The Common Lisp library Alexandria (installable through quicklisp) includes an implementation of copy-array for arbitrary ranks and dimensions:

    (defun copy-array (array &key
                       (element-type (array-element-type array))
                       (fill-pointer (and (array-has-fill-pointer-p array)
                                          (fill-pointer array)))
                       (adjustable (adjustable-array-p array)))
      "Returns an undisplaced copy of ARRAY, with same fill-pointer and
    adjustability (if any) as the original, unless overridden by the keyword
    arguments. Performance depends on efficiency of general ADJUST-ARRAY in the
    host lisp -- for most cases a special purpose copying function is likely to
    perform better."
      (let ((dims (array-dimensions array)))
        ;; Dictionary entry for ADJUST-ARRAY requires adjusting a
        ;; displaced array to a non-displaced one to make a copy.
        (adjust-array
         (make-array dims
                     :element-type element-type :fill-pointer fill-pointer
                     :adjustable adjustable :displaced-to array)
         dims)))
    
    0 讨论(0)
  • 2020-12-18 23:45

    UPDATE: Nowadays, alexandria has a copy-array very similar to the implementation given below. Use that.

    OBSOLETE ANSWER: I used the following, which I believed was better than the alexandria version at the time:

    (defun copy-array (array &key
                       (element-type (array-element-type array))
                       (fill-pointer (and (array-has-fill-pointer-p array)
                                          (fill-pointer array)))
                       (adjustable (adjustable-array-p array)))
      "Returns an undisplaced copy of ARRAY, with same fill-pointer and
    adjustability (if any) as the original, unless overridden by the keyword
    arguments."
      (let* ((dimensions (array-dimensions array))
             (new-array (make-array dimensions
                                    :element-type element-type
                                    :adjustable adjustable
                                    :fill-pointer fill-pointer)))
        (dotimes (i (array-total-size array))
          (setf (row-major-aref new-array i)
                (row-major-aref array i)))
        new-array))
    

    The problem with the alexandria version was that the adjust-array hack causes the result (at least on SBCL) to never be a simple-array, which some other libraries (e.g. opticl) expect. The above version also was faster for me.

    Someone else has published a very similar version in a different library, but I forgot the names of both person and library.

    0 讨论(0)
  • 2020-12-18 23:50

    If you want to do things the nice, functional, nondestructive way, then why do you even need to copy it?

    • if you're copying it in order to update it -- then you're not doing it the functional way.

    • if you're doing it the functional way -- then you don't need a copy. You can just pass it anywhere and everywhere.

    Maybe you want to transform it. In that case, you could use one of Lisp's many pure functions, such as mapcar or filter.

    0 讨论(0)
  • 2020-12-18 23:51

    It depends how your 2D array is represented, and what flavor of Lisp are you using.

    If you are using Common Lisp, then copy-seq could be useful.

    0 讨论(0)
提交回复
热议问题