How do I output a grid of characters from a list of characters?

Viewed 73

I have a list of characters that I want to print out as a grid of fixed column. For every line-width I want to print to a newline.

For example, I want

(#\Y #\q #\J #\u #\( #\t #\n #\m #\@ #\& #\c #\z #\x #\? #\} #\_ #\0 #\@ #\q #\r #\f #\/ #\I #\1 #\; #\B #\& #\O #\O #\O #\Y #\( #\n #\i #\0 #\B #\L #\h #\* #\# #\1 #\r #\? #\k #\& #\J #\J #\x #\# #\x #\i #\d #\Q #\o #\J #\J #\O #\o #\n #\_ #\v #\t #\r #\X #\c #\J #\X #\t #\z #\( #\) #\b #\C #\f #\x #\z #\d #\f #\Q #\t #\w)

To be displayed as:

YqJu(tnm@
&czx?}_0@
qrf/I1;B&
OOOY(ni0B
Lh*#1r?k&
JJx#xidQo
JJOon_vtr
XcJXtz()b
CfxzdfQtw

This is what I have tried:

(define (char-display char-list line-width)
  (for ([char (in-list char-list)]
        [i (in-range line-width)])
    (cond
      [(zero? i) (void)] ; to make sure modulo does not operate on zero
      [(zero? (modulo line-width i)) (display #\newline)]
      [else (display char)])))

On calling the function with the above list and line-width of 9 I get:


J
(tnm@[

What am I doing wrong? Is there a better way to do this?

3 Answers

Others have already provided good answers. I just want to point out in-slice, which can be helpful in cases like this.

(define (char-display char-list line-width)
  (for ([chars (in-slice line-width char-list)])
    (map display chars)
    (newline)))

In

(define (char-display char-list line-width)
  (for ([char (in-list char-list)]
        [i (in-range line-width)])
    ...))

The char and i runs through char-list and the numbers 0, 1, ..., linewidth-1 respectively. They do so in parallel. When one sequence is exhausted the loop stops. Here the number sequence is the shortest and you only see one line.

The first change is therefor to change the second for-clause to

[i (in-naturals)]

The second change is the order of arguments for modulo (they need to be swapped):

(modulo i line-width)

The third change is to always display a character. It is only the newline that may-or-may-not be displayed.

(define (char-display char-list line-width)
  (for ([char (in-list char-list)]
        [i    (in-naturals)])
    (when (zero? (modulo i line-width))
      (unless (zero? i)
        (newline)))
    (display char)))

This works:

(define (char-display char-list line-width)
  (for ([char (in-list char-list)]
        [i    (in-naturals 1)])
    (display char)
    (when (zero? (modulo i line-width))
      (newline))))

There were a couple of problems with your code:

  • Doing an (in-range line-width) will only produce integers up to line-width, you need to produce as many integers as characters in the list.
  • We can start the integer sequence at 1 to avoid having to handle the edge case at the beginning when it's zero.
  • The parameters to modulo were in the wrong order.
  • You have to display characters in all of the iterations, you were skipping a few when the modulo was zero.
Related