Print the contents of a multi-dimensional array

Discussion of Common Lisp
I X Code X 1
Posts: 59
Joined: Sun May 29, 2011 8:52 pm
Location: NY
Contact:

Print the contents of a multi-dimensional array

Post by I X Code X 1 » Wed Jul 27, 2011 7:52 am

Hello,

I am trying to print the contents of an Array of rank 2. However, I am getting this error:

Code: Select all


; At the moment it would just print a bunch of nils, but that's fine for the moment.

CG-USER(15): (defparameter *hi* (make-array '(5 5)))
*HI*
CG-USER(16): *hi*
#2A((NIL NIL NIL NIL NIL)
    (NIL NIL NIL NIL NIL)
    (NIL NIL NIL NIL NIL)
    (NIL NIL NIL NIL NIL)
    (NIL NIL NIL NIL NIL))
CG-USER(17): (loop for i across *hi* do (print i))
Error: attempt to take the length of a non-sequence:
       #<Array of rank 2 @ #x2122e832>
I know this of course would work if it was just a vector (one-dimension), but does Common Lisp have any method of printing the contents of a multi-dimensional array?

Thanks!

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Print the contents of a multi-dimensional array

Post by ramarren » Wed Jul 27, 2011 8:16 am

I'm not sure what you are asking. You can see the printed form of a multi-dimensional arrays right in your code example. Just use PRINT directly on an array. If you mean to print in a table form then just use a nested loop and iterate by indices.

I X Code X 1
Posts: 59
Joined: Sun May 29, 2011 8:52 pm
Location: NY
Contact:

Re: Print the contents of a multi-dimensional array

Post by I X Code X 1 » Wed Jul 27, 2011 9:21 am

Thanks,

I guess I was not aware you could just use PRINT directly on the array. Though that's not what I wanted. I want to print each row of the array as such

Code: Select all

; For the above I would want it to come out like this:

nil nil nil nil nil
nil nil nil nil nil
nil nil nil nil nil
nil nil nil nil nil
nil nil nil nil nil

; without the array marks, #2A(...)
Just not sure how to get at each individual row of the array.


EDIT: Alright, I think I understand how to do this now. Will need to do the nested loop as Ramarren posted. Thanks.

I X Code X 1
Posts: 59
Joined: Sun May 29, 2011 8:52 pm
Location: NY
Contact:

Re: Print the contents of a multi-dimensional array

Post by I X Code X 1 » Wed Jul 27, 2011 9:45 am

Code: Select all

(loop for i from 0 to 4 do
                   (loop for m from 0 to 4 collect (aref *hi* i m)))
This is returning NIL and not quite sure why. :|

Just using collect to see if I can figure this out.

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Print the contents of a multi-dimensional array

Post by ramarren » Wed Jul 27, 2011 9:47 am

I X Code X 1 wrote:This is returning NIL and not quite sure why.
The outer loop doesn't care about COLLECT in the inner loop. The outer loop has no clause which would cause a return value.

I X Code X 1
Posts: 59
Joined: Sun May 29, 2011 8:52 pm
Location: NY
Contact:

Re: Print the contents of a multi-dimensional array

Post by I X Code X 1 » Wed Jul 27, 2011 9:59 am

Ah yeah, I kinda knew that was the reason. Just didn't want it to be. Anyway though, I got it to do what I wanted it to. Might not be the best way, but it works:

Code: Select all

(loop for i from 0 to 4 do
      (format t "~a~&" (loop for m from 0 to 4 do 
                           (format t "~a" (aref *hi* i m)))))


NILNILNILNILNILNIL
NILNILNILNILNILNIL
NILNILNILNILNILNIL
NILNILNILNILNILNIL
NILNILNILNILNILNIL

Tried it with PRINT's and PRINC's, but the fact that it returns a NIL each time makes it look bad. Anyway to get it out of there? FORMAT only returns the NIL at the very end, which is nice.

Code: Select all

(loop for i from 0 to 4 do
      (print (loop for m from 0 to 4 do 
                           (princ (aref *hi* i m)))))

NILNILNILNILNIL
NIL NILNILNILNILNIL
NIL NILNILNILNILNIL
NIL NILNILNILNILNIL
NIL NILNILNILNILNIL
NIL 
NIL

EDIT: I made it a bit better, looks like I really only need the first FORMAT call. Can use princ after that.

Code: Select all

(loop for i from 0 to 4 do
      (format t "~a~&" (loop for m from 0 to 4 do 
                           (princ (aref *hi* i m)))))

NILNILNILNILNILNIL
NILNILNILNILNILNIL
NILNILNILNILNILNIL
NILNILNILNILNILNIL
NILNILNILNILNILNIL
Thanks for the help!

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Print the contents of a multi-dimensional array

Post by ramarren » Wed Jul 27, 2011 10:14 am

I X Code X 1 wrote:Ah yeah, I kinda knew that was the reason. Just didn't want it to be.
That is only one of many reasons I prefer iterate, which provides this exact feature. Unless the code walker somehow gets tangled.

Why do you have a printing operation in the outer loop? If I wanted to print an array I would do something like this:

Code: Select all

(defun print-2d-array-as-table (array)
  (loop for i from 0 below (array-dimension array 0)
        do (loop for j from 0 below (array-dimension array 1)
                 do (princ (aref array i j))
                    (if (= j (1- (array-dimension array 1)))
                        (terpri)
                        (princ #\Space)))))

I X Code X 1
Posts: 59
Joined: Sun May 29, 2011 8:52 pm
Location: NY
Contact:

Re: Print the contents of a multi-dimensional array

Post by I X Code X 1 » Wed Jul 27, 2011 10:22 am

Thanks, Ramarren!

I actually wasn't aware of ARRAY-DIMENSION. Iterate does look more appealing, definitely with the link you posted.

I X Code X 1
Posts: 59
Joined: Sun May 29, 2011 8:52 pm
Location: NY
Contact:

Re: Print the contents of a multi-dimensional array

Post by I X Code X 1 » Wed Jul 27, 2011 4:42 pm

This is what I was working on. Credit for the print-array function goes to Ramarren. Thanks for the help!

I just made a simple string generator. I work for a company and have to do a lot of QA-type things and one thing that I had to do the other day was to verify that text fields only allow the specified amount of characters. Got a little bit annoying to type it all out, even with copy and paste. So today on my down time I threw this together. Asks you for how many characters and how many lines you would like to have:

Code: Select all

(defun string-generator ()
  (format t "Please enter the amount of characters: ")
  (let ((c (read)))
    (format t "~&Please enter the amount of lines: ")
    (let* ((l (read))
           (a (make-array `(,l ,c))))  
                (map-into (make-array (reduce '* (array-dimensions a)) 
                                      :element-type 
                                      (array-element-type a) :displaced-to a) 
                          (lambda () (random 10)))
      (print-array a))))

(defun print-array (array)
  (loop for i from 0 below (array-dimension array 0)
        do (loop for j from 0 below (array-dimension array 1)
                 do (princ (aref array i j))
                 (if (= j (1- (array-dimension array 1)))
                     (terpri)))))

CG-USER(68): (string-generator)
Please enter the amount of characters: 20

Please enter the amount of lines: 20
56492889241784419519
12366116046700017433
02054109384718440791
53637470891442215430
37343259400359346410
26368560619707029259
41110582820691777328
59418319708063574168
96121143614027244294
08906379198745003444
05548522896607317289
30782460306116910908
73283493220236328021
39384296821902656149
34239764840990097742
38536812464963755711
48749151276399492348
03995008638774135280
10943530499981882575
23618230850678623681
NIL
This isn't that complex or anything, but taught me a lot about arrays in Common Lisp. Any tips to make it better or things that I should have done differently is appreciated.

Paul
Posts: 106
Joined: Tue Jun 02, 2009 6:00 am

Re: Print the contents of a multi-dimensional array

Post by Paul » Wed Jul 27, 2011 5:15 pm

Ramarren wrote:That is only one of many reasons I prefer iterate, which provides this exact feature. Unless the code walker somehow gets tangled.
(loop named <name> ...)

FWIW, you don't need two loops:

Code: Select all

(defun print-2d-array-as-table (array)
  (loop for i below (array-total-size array) do
    (if (zerop (mod i (array-dimension array 0)))
        (terpri)
        (princ #\Space))
    (princ (row-major-aref array i))))

Post Reply