fork download
  1. (defun calculate-level-sums (lst)
  2. "Вычисляет суммы чисел на каждом уровне вложенности списка lst.
  3. Возвращает список пар (уровень сумма), отсортированный по уровню."
  4. (prepare-result (calculate-level-sums-helper lst 1 '())))
  5.  
  6. (defun calculate-level-sums-helper (lst level acc)
  7. "Рекурсивная функция, которая проходит по списку lst на заданном уровне level,
  8. накапливая суммы чисел в аккумуляторе acc. Аккумулятор acc - это список пар (уровень сумма)."
  9. (cond
  10. ((null lst) acc) ; Базовый случай: если список пуст, возвращаем аккумулятор
  11. (t (let ((head (car lst)) ; Берем первый элемент списка
  12. (tail (cdr lst))) ; Берем остаток списка
  13. (multiple-value-bind (new-acc remaining-tail) ; Обрабатываем текущий элемент
  14. (process-item head level acc) ; Функция process-item определяет, что делать с элементом
  15. (calculate-level-sums-helper tail level new-acc)))))) ; Рекурсивно вызываем себя для остатка списка
  16.  
  17. (defun process-item (item level acc)
  18. "Обрабатывает один элемент item на заданном уровне level.
  19. Если элемент - число, обновляет аккумулятор.
  20. Если элемент - список, рекурсивно вызывает calculate-level-sums-helper для этого списка."
  21. (cond
  22. ((numberp item) ; Если элемент - число
  23. (values (update-level-sum acc level item) nil)) ; Обновляем сумму для уровня и возвращаем новый аккумулятор
  24. ((listp item) ; Если элемент - список
  25. (values (calculate-level-sums-helper item (1+ level) acc) nil)) ; Рекурсивно вызываем себя для списка, увеличив уровень
  26. (t (values acc nil)))) ; Если элемент - не число и не список (например, символ), просто игнорируем его
  27.  
  28. (defun update-level-sum (acc level value)
  29. "Обновляет аккумулятор acc суммой для заданного уровня level, добавляя value.
  30. Если уровень уже есть в аккумуляторе, добавляет value к существующей сумме.
  31. Иначе, добавляет новую пару (уровень value) в аккумулятор."
  32. (let ((existing (assoc level acc))) ; Ищем существующую запись для уровня
  33. (if existing ; Если уровень уже есть в аккумуляторе
  34. (let ((new-acc (remove existing acc :test #'equal))) ; Удаляем старую запись
  35. (cons (list level (+ value (cadr existing))) new-acc)) ; Добавляем обновленную запись с новой суммой
  36. (cons (list level value) acc)))) ; Иначе, добавляем новую пару (уровень value) в аккумулятор
  37.  
  38. (defun prepare-result (acc)
  39. "Подготавливает результат, сортируя аккумулятор по уровню и добавляя уровень 1 с суммой 0, если его нет."
  40. (if (assoc 1 acc) ; Проверяем, есть ли уровень 1 в аккумуляторе
  41. (sort acc #'< :key #'car) ; Если есть, сортируем аккумулятор по уровню
  42. (sort (cons '(1 0) acc) #'< :key #'car))) ; Иначе, добавляем (1 0) и сортируем
  43.  
  44. ;; Тесты
  45. (format t "~a~%" (calculate-level-sums '(a (b (4 (2 e (3) k 15) e 5) 7)))) ; ((1 0) (2 7) (3 9) (4 17) (5 3))
  46. (format t "~a~%" (calculate-level-sums '(a b c))) ; ((1 0))
  47. (format t "~a~%" (calculate-level-sums '(1 (2 (3))))) ; ((1 1) (2 2) (3 3))
  48. (format t "~a~%" (calculate-level-sums'(1 (2 3 (4 (5 6)))))) ; ((1 1) (2 5) (3 4) (4 11))
  49.  
Success #stdin #stdout #stderr 0.02s 9564KB
stdin
Standard input is empty
stdout
((1 0) (2 7) (3 9) (4 17) (5 3))
((1 0))
((1 1) (2 2) (3 3))
((1 1) (2 5) (3 4) (4 11))
stderr
Warning: reserving address range 0x80000c0000...0x1fffffffffff that contains memory mappings. clisp might crash later!
Memory dump:
  0x8000000000 - 0x80000bffff
  0x14b239400000 - 0x14b2396e4fff
  0x14b239815000 - 0x14b239839fff
  0x14b23983a000 - 0x14b2399acfff
  0x14b2399ad000 - 0x14b2399f5fff
  0x14b2399f6000 - 0x14b2399f8fff
  0x14b2399f9000 - 0x14b2399fbfff
  0x14b2399fc000 - 0x14b2399fffff
  0x14b239a00000 - 0x14b239a02fff
  0x14b239a03000 - 0x14b239c01fff
  0x14b239c02000 - 0x14b239c02fff
  0x14b239c03000 - 0x14b239c03fff
  0x14b239c80000 - 0x14b239c8ffff
  0x14b239c90000 - 0x14b239cc3fff
  0x14b239cc4000 - 0x14b239dfafff
  0x14b239dfb000 - 0x14b239dfbfff
  0x14b239dfc000 - 0x14b239dfefff
  0x14b239dff000 - 0x14b239dfffff
  0x14b239e00000 - 0x14b239e03fff
  0x14b239e04000 - 0x14b23a003fff
  0x14b23a004000 - 0x14b23a004fff
  0x14b23a005000 - 0x14b23a005fff
  0x14b23a0c1000 - 0x14b23a0c4fff
  0x14b23a0c5000 - 0x14b23a0c5fff
  0x14b23a0c6000 - 0x14b23a0c7fff
  0x14b23a0c8000 - 0x14b23a0c8fff
  0x14b23a0c9000 - 0x14b23a0c9fff
  0x14b23a0ca000 - 0x14b23a0cafff
  0x14b23a0cb000 - 0x14b23a0d8fff
  0x14b23a0d9000 - 0x14b23a0e6fff
  0x14b23a0e7000 - 0x14b23a0f3fff
  0x14b23a0f4000 - 0x14b23a0f7fff
  0x14b23a0f8000 - 0x14b23a0f8fff
  0x14b23a0f9000 - 0x14b23a0f9fff
  0x14b23a0fa000 - 0x14b23a0fffff
  0x14b23a100000 - 0x14b23a101fff
  0x14b23a102000 - 0x14b23a102fff
  0x14b23a103000 - 0x14b23a103fff
  0x14b23a104000 - 0x14b23a104fff
  0x14b23a105000 - 0x14b23a132fff
  0x14b23a133000 - 0x14b23a141fff
  0x14b23a142000 - 0x14b23a1e7fff
  0x14b23a1e8000 - 0x14b23a27efff
  0x14b23a27f000 - 0x14b23a27ffff
  0x14b23a280000 - 0x14b23a280fff
  0x14b23a281000 - 0x14b23a294fff
  0x14b23a295000 - 0x14b23a2bcfff
  0x14b23a2bd000 - 0x14b23a2c6fff
  0x14b23a2c7000 - 0x14b23a2c8fff
  0x14b23a2c9000 - 0x14b23a2cefff
  0x14b23a2cf000 - 0x14b23a2d1fff
  0x14b23a2d4000 - 0x14b23a2d4fff
  0x14b23a2d5000 - 0x14b23a2d5fff
  0x14b23a2d6000 - 0x14b23a2d6fff
  0x14b23a2d7000 - 0x14b23a2d7fff
  0x14b23a2d8000 - 0x14b23a2d8fff
  0x14b23a2d9000 - 0x14b23a2dffff
  0x14b23a2e0000 - 0x14b23a2e2fff
  0x14b23a2e3000 - 0x14b23a2e3fff
  0x14b23a2e4000 - 0x14b23a304fff
  0x14b23a305000 - 0x14b23a30cfff
  0x14b23a30d000 - 0x14b23a30dfff
  0x14b23a30e000 - 0x14b23a30efff
  0x14b23a30f000 - 0x14b23a30ffff
  0x55cb4b87f000 - 0x55cb4b96ffff
  0x55cb4b970000 - 0x55cb4ba79fff
  0x55cb4ba7a000 - 0x55cb4bad9fff
  0x55cb4badb000 - 0x55cb4bb09fff
  0x55cb4bb0a000 - 0x55cb4bb3afff
  0x55cb4bb3b000 - 0x55cb4bb3efff
  0x55cb4cff3000 - 0x55cb4d013fff
  0x7ffe2b576000 - 0x7ffe2b596fff
  0x7ffe2b5b8000 - 0x7ffe2b5bbfff
  0x7ffe2b5bc000 - 0x7ffe2b5bdfff