Как генерировать индексы списка с помощью директив формата - PullRequest
4 голосов
/ 29 апреля 2020

Есть ли способ получить тот же вывод, что и этот: (Рука - это список карт)

(loop for card in hand
           with i = 1
           do
             (format t "~&~a. ~a~%" i card)
             (incf i))
1. (5 . HEARTS)
2. (5 . CLUBS)
3. (10 . DIAMONDS)
4. (JACK . DIAMONDS)
5. (8 . CLUBS)

, но использовать только один вызов для форматирования? Пока что у меня есть это, но я не знаю, как увеличить индекс.

(format nil "~{~%1. ~a~}~%" hand)
1. (5 . HEARTS)
1. (5 . CLUBS)
1. (10 . DIAMONDS)
1. (JACK . DIAMONDS)
1. (8 . CLUBS)

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

(let ((counter 0))
  (defun increment (output-stream format-argument colonp at-sign-p &rest directive-parameters)
    (declare (ignore colonp at-sign-p directive-parameters))
    (incf counter)
    (format output-stream "~a. ~a" counter format-argument))
  (defun reset-counter ()
    (setf counter 0)))

(format t "~&~{~&~/increment/~}" '(a c b d))
1. A
2. C
3. B
4. D

Ответы [ 2 ]

8 голосов
/ 29 апреля 2020

Ваша форма l oop:

(loop for card in hand
           with i = 1
           do
             (format t "~&~a. ~a~%" i card)
             (incf i))

Обычно пишут это как:

(loop for card in hand and i from 1
      do (format t "~&~a. ~a~%" i card))

Один из способов решить проблему - предоставить список с номерами :

(defun numbering (list &key (i0 1))
  (loop for i from i0 and element in list
        collect i collect element))

CL-USER > (format t "~{~%~a. ~a~}~%" (numbering hand))

1. (5 . HEARTS)
2. (5 . CLUBS)
3. (10 . DIAMONDS)
4. (JACK . DIAMONDS)
5. (8 . CLUBS)
NIL
5 голосов
/ 29 апреля 2020

Самый простой способ для меня - это здесь oop. Я бы написал следующую функцию:

(defun format-hand (stream hand)
  (loop
     with width = (ceiling (log (length hand) 10))
     for index from 1
     for (value . color) in hand
     do (format stream "~&~vd. ~@(~a~) of ~(~a~)" width index value color)))

Партию width можно опустить, если вы знаете, что в руке никогда не бывает более 9 карт. Используется для выравнивания индексов в форматированном выводе. Например, с очень длинной рукой:

(let ((hand '((5 . hearts) (5 . clubs) (10 . diamonds) 
              (jack . diamonds) (8 . clubs))))
  (format-hand t (concatenate 'list hand hand hand hand)))

 1. 5 of hearts
 2. 5 of clubs
 3. 10 of diamonds
 4. Jack of diamonds
 5. 8 of clubs
 6. 5 of hearts
 7. 5 of clubs
 8. 10 of diamonds
 9. Jack of diamonds
10. 8 of clubs
11. 5 of hearts
12. 5 of clubs
13. 10 of diamonds
14. Jack of diamonds
15. 8 of clubs
16. 5 of hearts
17. 5 of clubs
18. 10 of diamonds
19. Jack of diamonds
20. 8 of clubs

Другой пример с причудливыми символами Юникода (см. GETF):

(defun format-hand (stream hand)
  (loop
     with width = (ceiling (log (length hand) 10))
     for index from 1
     for (value . color) in hand
     for symbol = (getf '(hearts "♥" diamonds "♦" spades "♠" clubs "♣") color)
     do (format stream "~&~vd. ~a ~a" width index symbol value)))

(format-hand t '((5 . hearts) (5 . clubs) (10 . diamonds)
               (jack . diamonds) (8 . clubs)))

1. ♥ 5
2. ♣ 5
3. ♦ 10
4. ♦ JACK
5. ♣ 8
...