Comment obtenir le numéro d'élément dans une liste?

16

Q: comment obtenir le numéro d'élément dans une liste?

nthobtient l'élément numéro n d'une liste:

(nth 2 '(a b c d))                      ; => c

Je voudrais faire l'inverse: obtenir le numéro d'élément étant donné l'élément:

(some-function 'c '(a b c d))           ; => 2

Je l'ai peut-être manqué, mais une telle fonction existe-t-elle? Comment ferait-on cela?

Dan
la source

Réponses:

22
  1. Voici une fonction incluse avec Emacs 24.3 et versions ultérieures:
(cl-position 2 '(6 7 8 2 3 4)) ;; => 3

(Avant Emacs 24.3, utilisez la fonction positionde la bibliothèque cl.el, qui est incluse avec Emacs.)

Vous pouvez utiliser le :testmot - clé pour spécifier la fonction de comparaison:

(cl-position "bar" '("foo" "bar" "baz") :test 'equal) ;; => 1
(cl-position '(1 2) '((3) (5 6) (1 2) nil) :test 'equal) ;; => 2

Emacs Common Lisp Emulation Manual

  1. dash.el a une fonction qui peut le faire: -elem-index
(-elem-index 2 '(6 7 8 2 3 4)) ;; => 3
(-elem-index "bar" '("foo" "bar" "baz")) ;; => 1
(-elem-index '(1 2) '((3) (5 6) (1 2) nil)) ;; => 2

Ce n'est pas inclus avec Emacs, mais beaucoup d'utilisateurs d' Emacs ont déjà installé (il est une dépendance de projectile, flychecket smartparens, ce qui lui donne une tonne de couverture).

nounou
la source
6

Eh bien, si vous voulez rouler le vôtre au lieu d'utiliser cl-position, et que vous ne voulez pas traverser deux fois (en utilisant length) ...

(defun nth-elt (element xs)
  "Return zero-indexed position of ELEMENT in list XS, or nil if absent."
  (let ((idx  0))
    (catch 'nth-elt
      (dolist (x  xs)
        (when (equal element x) (throw 'nth-elt idx))
        (setq idx  (1+ idx)))
      nil)))

C'est bon même pour les anciennes versions d'Emacs. Cependant, il a cette différence de comportement, que vous souhaitiez ou non: il fonctionne également pour les voitures d'une liste en pointillés. Autrement dit, il renvoie correctement la position au lieu de générer une erreur, pour les sexps tels que (nth-elt 'c '(a b c . d)).

Si vous souhaitez toujours générer une erreur pour une liste incorrecte, alors vous voudrez vérifier ce cas, ce qui nécessite de toujours parcourir jusqu'à la fin de la liste:

(defun nth-elt (element xs)
  "Return zero-indexed position of ELEMENT in list XS, or nil if absent."
  (let ((idx  0))
    (when (atom (cdr (last xs))) (error "Not a proper list"))
    (catch 'nth-elt
      (dolist (x  xs)
        (when (equal element x) (throw 'nth-elt idx))
        (setq idx  (1+ idx)))
      nil)))
A dessiné
la source
2

Il s'avère que c'est une fonction simple à écrire, bien qu'elle ne soit pas si efficace:

(defun nth-elt (elt list)
  "Return element number of ELT in LIST."
  (let ((loc (length (member elt list))))
    (unless (zerop loc)
      (- (length list) loc))))

(nth-elt 'c '(a b c d))                 ; => 2
(nth-elt 'f '(a b c d))                 ; => nil

Je préfère une solution intégrée s'il en existe une, bien sûr.

Dan
la source