Здесь функция. Я создаю два списка, а затем объединяю их.
(defun my-rotate (length shift)
"Return a list of given LENGTH, rotated by SHIFT."
(nconc
(loop for i from (1+ shift) to (- length shift -2) collect i)
(loop for i from 1 to shift collect i)))
(my-rotate 7 2)
==> (3 4 5 6 7 1 2)
Обратите внимание, что поскольку оба loop
s производят fresh списки, я использую nconc
вместо append
.
Если, однако, вы хотите, чтобы повернуть существующий список, вам нужно будет сделать что-то другое:
(defun rotate-list (list shift)
"Rotate the given LIST by the specified SHIFT."
(let ((len (length list)))
(setq shift (mod shift len)) ; handle circular shifts
(append (nthcdr (- len shift) list)
(butlast list shift))))
(rotate-list '(1 2 3 4 5 6) 2)
==> (5 6 1 2 3 4)
(rotate-list '(1 2 3 4 5 6) 20)
==> (5 6 1 2 3 4) ; same because 20 = 2 mod 6
(rotate-list '(1 2 3 4 5 6) 0)
==> (1 2 3 4 5 6) ; unchanged
Обратите внимание, что nthcdr
точки внутри исходного списка, так что мы должны использовать append
, чтобы избежать модифицируя аргумент.
Заметим также, что мы сканируем list
аргумент дважды (один раз в nthcdr
и один раз в butlast
). Если ваши списки огромны, а профилирование показывает, что эта функция является узким местом, вы можете переписать ее с помощью цикла (это сценарий настолько маловероятен, что я уже сожалею о том, что потерял время, написав эту заметку).
Что это такое? Могут быть лучшие способы достижения вашей общей цели. – blambert