Для хобби-проекта я имею дело со списками a-списков, таких как
((0 . 0) (0 . 1) (0 . 3) (0 . 4) (0 . 7) (0 . 8))
, где список может содержать до девяти элементов, а a-списки состоят только из целых чисел из0
до 9
.Я хочу разбить список на подузлы с последовательными cdr
с.
(((0 . 0) (0 . 1)) ((0 . 3) (0 . 4)) ((0 . 7) (0 . 8)))
Подразделение может иметь только один элемент, а список не может иметь подэлементов.единица измерения, например:
((0 . 0) (0 . 1) (0 . 2) (0 . 4))
или ((0 . 0) (0 . 1) (0 . 2) (0 . 3) (0 . 4))
Результаты должны быть следующими:
(((0 . 0) (0 . 1)) ((0 . 3) (0 . 4)) ((0 . 7) (0 . 8)))
(((0 . 0) (0 . 1) (0 . 2)) ((0 . 4)))
(((0 . 0) (0 . 1) (0 . 2) (0 . 3) (0 . 4)))
Использование iterate Я предложил двухэтапный подход.Во-первых, отсканируйте список и проверьте, есть ли подразделения или нет, возвращая позиции промежутков.А во-вторых, разделите список на части с помощью функции split-at
, которую я реализовал ранее:
(defun split-at (count original-list)
(unless (or (null original-list) (minusp count)
(>= count (length original-list)))
(list (subseq original-list 0 count)
(subseq original-list count))))
(defun sub-units (units)
"Scan UNITS for sub-units."
(iter
(for (a . b) in units)
(for last-b previous b initially -1)
(for pos from 0)
(unless (= 1 (- b last-b))
(collecting pos))))
(defun split-sub-units (units)
"Splits UNITS into its sub-units."
(iter
(with pos = (or (sub-units units) (list 0)))
(for p in pos)
(for last-p previous p)
(for (head tail) first (split-at p units) then (split-at last-p tail))
(when head
(collect head into result))
(finally (return (nconc result (list tail))))))
Можно ли объединить две функции sub-units
и split-sub-units
в одну?Есть ли разница в стиле или эффективности?