Решение
shuffle
действительно хорошее решение и очень функциональное.Функциональный стиль запрещает мутацию / изменение существующих / определенных значений переменных (таким образом, нет set!
).Скорее каждый создает / копирует существующий объект и мутирует его или создает его в видоизмененном виде.shuffle
создает / копирует исходный список в мутированном порядке.
Вы можете использовать take
и drop
, чтобы получить или покинуть первую n
позицию любого списка.Или используйте функцию split-at
.
Однако, поскольку это возвращает результат в виде значений, а задача заключалась в возвращении списка, вы используете let-values
, чтобы связать два возвращаемых результата и связать их в один список.
(define (choose-n-and-rest lst n)
(let-values ([(chosen rest) (split-at (shuffle lst) n)])
(list chosen rest)))
или:
(define (choose-n-and-rest lst n)
(let ((new-lst (shuffle lst)) ; so that `take` & `drop` use the same shuffled list
(list (take new-list n) (drop new-list n))))
Но, как вы можете прочитать здесь , split-at
может быть несколько более эффективным, чем комбинация take
и drop
.
Попробуйте это с помощью:
(choose-n-and-rest '(a b c d e 1 2 3 4 5) 3)
;; e.g. '((a 4 2) (1 b 3 5 c e d))
Кстати, set!
или лучше: мутирующие функции полностью запрещены в функциональном программировании в стиле lisp.Причина в производительности.Копирование каждого длинного списка стоит дорого.Примером является nreverse
Common-lisp, который изменяет порядок исходного списка (меняет порядок).Немутация reverse
создает новый список с элементами в обратном порядке.Но для этого он должен скопировать.Если вы изменяете локальные переменные (определяемые let
), это может привести к повышению производительности, но, конечно, очень осторожно, поскольку мутация опасна.