Comment puis-je mapper sur un vecteur et obtenir un vecteur?


15

La seule chose que j'ai trouvée qui fonctionne est

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

mais cela semble beaucoup trop compliqué pour être la «bonne» façon.

Réponses:


19

Utilisez cl-mapplutôt:

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

Un petit arrière-plan supplémentaire: cl-mapest la fonction Common Lispmap qui se généralise aux types de séquence:

(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"

Il peut également convertir entre les types de séquence (par exemple, ici, l'entrée est une liste et la sortie est un vecteur):

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

1
18 secondes le «gagnant» :) Les clbibliothèques ne donnent-elles pas d'avertissements au compilateur, cependant? (Surtout parce que la FSF est odieuse?)
Sean Allred

1
FWIW, je pense que les problèmes de compilation d'octets étaient liés à l'ancienne clbibliothèque plutôt qu'à la cl-libbibliothèque relancée . Je ne suis pas, par exemple, obtenir des avertissements quand je (defun fnx () (cl-map 'vector #'1+ '[1 2 3 4]))puis (byte-compile 'fnx).
Dan

2
Même si vous utilisez la compatibilité cl-lib, je pense que vous obtiendrez des avertissements sur les anciens emacs (24.2). Je ne m'en inquiéterais pas cependant, vous devez choisir vos batailles.
Malabarba

16

Depuis que j'ai été battu de 18 secondes, voici un moyen plus simple et plus sûr de le faire sans la bibliothèque cl. Il n'évalue pas non plus les éléments.

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

C'est aussi assez sympa! Re: votre commentaire précédent sur les Emacs plus anciens: cela semble particulièrement utile si vous devez anticiper les utilisateurs hérités. Cela semble plus utile si vous ne devez l'utiliser que dans quelques endroits, à quel point vous pouvez échanger le léger inconvénient contre éviter la cl-libdépendance.
Dan

1
Très chouette !! Je n'ai pas pensé à utiliser apply.
Sean Allred

Je pense que cela (apply #'vector ...)pourrait être un peu plus rapide, mais pour être complet, il peut également être remplacé par (vconcat ...).
Basil

1

La variante inplace pas si élégante pour le cas où le vecteur d'origine n'est plus nécessaire par la suite et l'allocation de mémoire est critique en temps (par exemple, le vecteur est grand).

(setq x [1 2 3 4])

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

Le résultat est stocké dans x. Si vous avez besoin du formulaire pour retourner xà la fin, vous pouvez ajouter finally return xcomme suit:

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

1

Pour être complet, utilisez seq:

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

Il y a une réponse supprimée de Fólkvangr 2018-11-12 avec exactement la même seq-intoligne. L'utilisateur a supprimé sa réponse pour la raison suivante: "Ma solution est moins pertinente car la bibliothèque seq utilise les extensions Common Lisp sous-jacentes. - Fólkvangr 16 mai à 8:53"
Tobias

@Tobias Je suppose que je ne suis pas d'accord avec cette logique. Tout va finir par utiliser vconcat ou vector de toute façon, mais les différents paradigmes d'interface sont utiles à enregistrer.
Sean Allred

Aucun problème. Je viens de voir la réponse supprimée de Fólkvangr (presque) correspondant à la vôtre et je voulais vous en informer. Pour une raison quelconque, voir les réponses supprimées nécessite 10000 répétitions :-(.
Tobias

@Tobias ouais, je n'ai jamais vraiment compris pourquoi ces privilèges étaient spécifiques au site :-)
Sean Allred

0

Vous pouvez utiliser la boucle

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

Parfois, vous ne voulez pas modifier le vecteur d'origine, vous pouvez en faire une copie

(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])

ou créez un nouveau vecteur à partir de zéro

(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])
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.