Как я могу нанести на карту вектор и получить вектор?


15

Единственное, что я нашел, это работает

(eval `(vector ,@(mapcar #'1+ [1 2 3 4])))
=> [2 3 4 5]

но кажется , что далеко слишком сложно , чтобы быть «правильный» путь.

Ответы:


19

Используйте cl-mapвместо этого:

(cl-map 'vector #'1+ [1 2 3 4])

Немного дополнительного фона: cl-mapэто функция Common Lisp,map которая обобщает типы последовательностей:

(cl-map 'vector #'1+ '[1 2 3 4]) ;; ==> [2 3 4 5]
(cl-map 'list   #'1+ '(1 2 3 4)) ;; ==> (2 3 4 5)
(cl-map 'string #'upcase "abc")  ;; ==> "ABC"

Он также может преобразовывать типы последовательностей (например, здесь вход является списком, а выход - вектором):

(cl-map 'vector #'1+ '(1 2 3 4)) ;; ==> [2 3 4 5]

1
18 секунд - победитель :) Разве clбиблиотеки не выдают предупреждения компилятора? (Главным образом потому, что ФСФ противна?)
Шон Оллред

1
FWIW, я думаю, что проблемы с байтовой компиляцией были связаны со старой clбиблиотекой, а не с перенастроенной cl-libбиблиотекой. Я, например, не получаю никаких предупреждений, когда я, (defun fnx () (cl-map 'vector #'1+ '[1 2 3 4]))а затем (byte-compile 'fnx).
Дан

2
Даже если вы используете cl-lib для совместимости, я думаю, вы получите предупреждения о старых emacs (24.2). Я бы не волновался об этом, ты должен выбрать свои сражения.
Малабарба

16

Поскольку меня избили 18 секунд, вот более простой и безопасный способ сделать это без библиотеки cl. Это также не оценивает элементы.

(apply #'vector (mapcar #'1+ [1 2 3 4])) ;; => [2 3 4 5]

Это тоже довольно приятно! Re: ваш предыдущий комментарий о старых Emacs: он кажется особенно полезным, если вы ожидаете старых пользователей. Это кажется наиболее полезным, если вам нужно использовать его только в нескольких местах, после чего вы можете обойтись без незначительных неудобств и избежать cl-libзависимости.
Дан

1
Очень изящно !! Я не думал об использовании apply.
Шон Оллред

Я думаю, что (apply #'vector ...)может быть немного быстрее, но для полноты его также можно заменить на (vconcat ...).
Василий

1

Не очень элегантный вариант на месте для случая, когда исходный вектор больше не нужен, а распределение памяти критично ко времени (например, вектор большой).

(setq x [1 2 3 4])

(cl-loop for var across-ref x do
         (setf var (1+ var)))

Результат сохраняется в x. Если вам нужна форма для возврата xв конце, вы можете добавить finally return xследующее:

(cl-loop for var across-ref x do
         (setf var (1+ var))
         finally return x)

1

Для полноты, используя seq:

(require 'seq)
(seq-into (seq-map #'1+ [1 2 3 4]) 'vector)

От Fólkvangr 2018-11-12 есть удаленный ответ с точно такой же seq-intoстрокой. Пользователь удалил свой ответ по следующей причине: «Мое решение менее актуально, потому что библиотека seq использует базовые расширения Common Lisp. - Fólkvangr 16 мая в 8:53»
Тобиас

@ Тобиас Я думаю, я бы не согласился с этой логикой. В любом случае все закончится использованием vconcat или vector, но различные парадигмы интерфейса полезно иметь при записи.
Шон Оллред

Нет проблем. Я только что увидел удаленный ответ Fólkvangr (почти) совпадающий с вашим и хотел уведомить вас. По какой-либо причине для просмотра удаленных ответов требуется 10000 представителей :-(.
Тобиас

@Tobias да, я так и не понял, почему эти привилегии были
Шон Оллред

0

Вы можете использовать цикл

(let ((v (vector 1 2 3 4)))
  (dotimes (i (length v))
    (aset v i (1+ (aref v i))))
  v)
;; => [2 3 4 5]

Иногда вы не хотите изменять исходный вектор, вы можете сделать копию

(let* ((v0 (vector 1 2 3 4))
       (v (copy-sequence v0)))
  (dotimes (i (length v))
    (aset v i (1+ (aref v i))))
  (list v0 v))
;; => ([1 2 3 4] [2 3 4 5])

или создайте новый вектор с нуля

(let* ((v0 (vector 1 2 3 4))
       (v (make-vector (length v0) nil)))
  (dotimes (i (length v))
    (aset v i (1+ (aref v0 i))))
  (list v0 v))
;; => ([1 2 3 4] [2 3 4 5])
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.