Como obter o número do elemento em uma lista?


16

P: como obtenho o número do elemento em uma lista?

nthobtém o número do elemento n de uma lista:

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

Eu gostaria de fazer o inverso: obter o número do elemento dado o elemento:

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

Eu posso ter esquecido, mas existe essa função? Como alguém faria isso?

Respostas:


22
  1. Aqui está uma função que está incluída no Emacs 24.3 e posterior:
(cl-position 2 '(6 7 8 2 3 4)) ;; => 3

(Antes do Emacs 24.3, use a função positionda biblioteca cl.el, incluída no Emacs.)

Você pode usar a :testpalavra-chave para especificar a função de comparação:

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

Manual de emulação Emacs Common Lisp

  1. dash.el tem uma função que pode fazer isso: -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

Não está incluído com o Emacs, mas um monte de usuários do Emacs já tê-lo instalado (é uma dependência projectile, flychecke smartparens, o que lhe dá uma tonelada de cobertura).


6

Bem, se você quiser criar o seu próprio, em vez de usar cl-position, e não quiser percorrer duas vezes (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)))

Isso é bom para versões antigas do Emacs. No entanto, possui essa diferença de comportamento, que você pode ou não querer: Funciona também para os carros de uma lista pontilhada. Ou seja, ele retorna corretamente a posição em vez de gerar um erro, para sexps como (nth-elt 'c '(a b c . d)).

Se você sempre deseja gerar um erro para uma lista imprópria, verifique esse caso, que exige sempre a passagem para o final da lista:

(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

Acontece que é uma função simples de escrever, embora possa não ser tão eficiente assim:

(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

Eu preferiria uma solução embutida, se houver, é claro.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.