Печать списка Lisp - PullRequest
       6

Печать списка Lisp

4 голосов
/ 10 ноября 2011

У меня проблемы с функцией формата lisp.У меня есть следующий список:

((X X X)(X X X X X X)(X X X X X X X X X)) 

, и мне нужно распечатать его в следующем формате:

X  X  X
XX XX XX
XXXXXXXXX

Есть мысли о том, как этого добиться?Функция форматирования немного сбивает с толку, и документация HyperSpec, похоже, ничего не делает для меня.Спасибо.

Ответы [ 2 ]

3 голосов
/ 11 ноября 2011

Как и у любого инструмента format, есть свои ограничения, и он не очень хорошо подходит для таких задач.Вероятно, лучшее, что вы можете получить в простом формате, не прибегая к уловкам черной магии с ~? или ~/, которые вы или кто-либо еще, вероятно, не поймете в будущем, это код:

CL-USER> (format t "~{~{~A ~}~%~}"
                 '((X X X) (X X X X X X) (X X X X X X X X X)))
X X X 
X X X X X X 
X X X X X X X X X 

Если вы хотите получить сложную структуру вывода, попробуйте выполнить некоторую предварительную обработку.Например, если формат списка жестко запрограммирован, вы можете использовать это:

(format t "~{~{~6A~} ~%~}"
          (mapcar (lambda (l)
                    (loop :for i :from 0 :to (1- (length l)) :by (/ (length l) 3)
                          :collect (format nil "~{~A ~}"
                                           (subseq l i (+ i (/ (length l) 3))))))
                  '((X X X) (X X X X X X) (X X X X X X X X X))))

Здесь мы сначала собираем элементы списка в одинаковое количество групп для каждого списка, печатаем их и такполучить 3 списка с одинаковым количеством элементов, которые затем можно обработать с помощью format.

Подробнее о format вы можете узнать в соответствующей главе превосходной книги Лиспа Питера Сейбела: http://gigamonkeys.com/book/a-few-format-recipes.html

РЕДАКТИРОВАТЬ

Если у вас есть переменное количество списков, каждый из которых в два раза больше предыдущего, вам также необходимо заранее подготовить строку формата:

CL-USER> (defun format-custom-list (list)
           (format t (format nil "~~{~~{~~~DA~~} ~~%~~}" (* 2 (length list)))
                   (mapcar (lambda (l)
                             (let* ((len (length l))
                                    (len/3 (/ len 3)))
                               (loop :for i :from 0 :to (1- len) :by len/3 
                                     :collect (format nil "~{~A ~}"
                                                      (subseq l i (+ i len/3))))))
                           list)))
CL-USER> (format-custom-list '((X X X) (X X X X X X) (X X X X X X X X X)
                               (X X X X X X X X X X X X)))
X       X       X        
X X     X X     X X      
X X X   X X X   X X X    
X X X X X X X X X X X X  
NIL

(Конечный nil - это вывод format, который не выводится в выходной поток t. Если вы хотите получить строку из этой функции, используйте nil как format выходной поток.) ​​

2 голосов
/ 10 ноября 2011

Я предполагаю, что вы хотите напечатать каждый список, вставляя пробелы, чтобы элементы соответствовали максимальной длине списка.

Хотя я считаю, что это можно напечатать почти одним вызовом format, лучше разделить печать на несколько функций:

(defun format-list (stream lst space-count)
  (let ((spaces (make-string 5 :initial-element #\Space))) ;; create string of spaces to insert
    (let ((fmt (concatenate 'string "~{~a" spaces "~}~%")) ;; create formatting string
      (format stream fmt lst)))))

(defvar full-list '((X X X)(X X X X X X)(X X X X X X X X X)))
(defvar max-list-length (max (mapcar length full-list)))  ;; find length 
(mapcar 
  #'(lambda (lst) (format-list t lst (/ (- max-list-length (length lst)) (length lst)))) 
  full-list)

UPD.

Для условия X + Space * (NumRows - CurrentRowNumber) вы можете использовать следующую функцию вместо 2 последних строк в моем исходном коде (в функциональном стиле вы также можете использовать loop вместо reduce, чтобы сделать его менее функциональным и более CL-как):

(format-list-of-lists (lst)
  (let ((num-rows (length lst))) 
    (reduce #(lambda (cur-row sub-list) (format-list t sub-list (- num-rows cur-row)) (1+ cur-row)) 
            lst)))
...