Як я можу відобразити вектор і отримати вектор?


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це загальна mapфункція Lisp, яка узагальнює типи послідовностей:

(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бібліотеки не попереджають компілятора? (Переважно тому, що FSF викликає неприємність?)
Шон Аллред

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рядком. Користувач видалив свою відповідь з наступної причини: "Моє рішення менш релевантне, оскільки бібліотека послідовностей використовує основні розширення Lisp. - Fólkvangr 16 травня о 8:53"
Tobias

@Tobias Я певно не погоджуюся з цією логікою. Все в кінцевому підсумку з використанням 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.