Common Lisp: convert between lists and arrays
Asked Answered
G

3

27

How do we convert elegantly between arbitrarily nested lists and arrays?

e.g.

((1 2 3) (4 5 6))

becomes

#2A((1 2 3) (4 5 6))

and vice versa

Gumbotil answered 3/3, 2012 at 20:24 Comment(0)
B
27

List to 2d array:

(defun list-to-2d-array (list)
  (make-array (list (length list)
                    (length (first list)))
              :initial-contents list))

2d array to list:

(defun 2d-array-to-list (array)
  (loop for i below (array-dimension array 0)
        collect (loop for j below (array-dimension array 1)
                      collect (aref array i j))))

The multi-dimensional form for list to 2d is easy.

(defun list-dimensions (list depth)
  (loop repeat depth
        collect (length list)
        do (setf list (car list))))

(defun list-to-array (list depth)
  (make-array (list-dimensions list depth)
              :initial-contents list))

The array to list is more complicated.

Maybe something like this:

(defun array-to-list (array)
  (let* ((dimensions (array-dimensions array))
         (depth      (1- (length dimensions)))
         (indices    (make-list (1+ depth) :initial-element 0)))
    (labels ((recurse (n)
               (loop for j below (nth n dimensions)
                     do (setf (nth n indices) j)
                     collect (if (= n depth)
                                 (apply #'aref array indices)
                               (recurse (1+ n))))))
      (recurse 0))))
Blackberry answered 3/3, 2012 at 20:46 Comment(2)
@mck: specify how many levels you want and give the right list of dimensions to MAKE-ARRAY.Blackberry
that would require writing a separate function for 3d-arrays?Gumbotil
C
9

Use coerce: Coerce the Object to an object of type Output-Type-Spec.

(coerce '(1 2 3) 'vector) => #(1 2 3)
(coerce #(1 2 3) 'list)   => '(1 2 3)
Callboy answered 6/2, 2020 at 10:25 Comment(1)
This only works for 1D lists or vectors, not for arrays of more than 1 dimension (See original question).Gesture
S
8

Another 2d array to list solution:

(defun 2d-array-to-list (array)
  (map 'list #'identity array))

And list to 2d array (But maybe not as efficient as the solution of the last reply):

(defun list-to-2d-array (list)
  (map 'array #'identity list))
Suellen answered 27/9, 2014 at 8:59 Comment(3)
Hmm... this doesn't seem to work for me; on a machine running SBCL 1.4.5, if I load the above defuns, and then try (2d-array-to-list #2A((1 2) (3 4))), I get: The value #2A((1 2) (3 4)) is not of type VECTOR. Similarly, if I try (list-to-2d-array '((1 2) (3 4))), I get ARRAY is a bad type specifier for sequences. So... Am I doing something wrong? Does this only work in some common lisp implementations? Is this from some other lisp? Other?Combes
MAP result-type must be a subtype of LIST or VECTOR, not ARRAY. That's why your LIST-TO-2D-ARRAY does not work. lispworks.com/documentation/HyperSpec/Body/f_map.htmGesture
Doesn’t work: ARRAY is a bad type specifier for sequences.Buonomo

© 2022 - 2024 — McMap. All rights reserved.