Come ottenere il numero di elemento in un elenco?


16

D: come posso ottenere il numero di elemento in un elenco?

nthottiene l'elemento numero n da un elenco:

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

Vorrei fare il contrario: ottenere il numero dell'elemento dato l'elemento:

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

Potrei averlo perso, ma esiste una tale funzione? Come si farebbe questo?

Risposte:


22
  1. Ecco una funzione inclusa in Emacs 24.3 e successive:
(cl-position 2 '(6 7 8 2 3 4)) ;; => 3

(Prima di Emacs 24.3, utilizzare la funzione positiondalla libreria cl.el, inclusa in Emacs.)

È possibile utilizzare la :testparola chiave per specificare la funzione di confronto:

(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 ha una funzione che può fare questo: -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

Non è incluso con Emacs, ma un sacco di utenti Emacs già averlo installato (è una dipendenza di projectile, flychecke smartparens, che gli conferisce una tonnellata di copertura).


6

Bene, se vuoi tirare il tuo invece di usare cl-position, e non vuoi attraversare due volte (usando 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)))

Va bene anche per le vecchie versioni di Emacs. Tuttavia, ha questa differenza di comportamento, che potresti o non vorrai: funziona anche per le auto di un elenco punteggiato. Cioè, restituisce correttamente la posizione invece di generare un errore, per sexp come (nth-elt 'c '(a b c . d)).

Se si desidera sempre generare un errore per un elenco non corretto, è necessario verificare tale caso, che richiede sempre di attraversare fino alla fine dell'elenco:

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

2

Si scopre che è una funzione semplice da scrivere, anche se potrebbe non essere così efficiente:

(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

Preferirei una soluzione integrata se ne esiste una, ovviamente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.