Jak uzyskać numer elementu na liście?

17

P: Jak mogę uzyskać numer elementu na liście?

nthpobiera numer elementu n z listy:

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

Chciałbym zrobić odwrotnie: pobierz numer elementu, biorąc pod uwagę element:

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

Mogłem to przegapić, ale czy taka funkcja istnieje? Jak by to zrobić?

Dan
źródło

Odpowiedzi:

22
  1. Oto funkcja zawarta w Emacsie 24.3 i nowszych:
(cl-position 2 '(6 7 8 2 3 4)) ;; => 3

(Przed Emacsem 24.3 użyj funkcji positionz biblioteki cl.el, która jest dołączona do Emacsa.)

Możesz użyć :testsłowa kluczowego, aby określić funkcję porównania:

(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 ma funkcję, która może to zrobić: -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

To nie jest dołączona Emacs, ale wielu użytkowników Emacs już go zainstalowanego (jest to zależność projectile, flychecki smartparens, co daje mu mnóstwo pokrycia).

niania
źródło
6

Cóż, jeśli chcesz rzucić własny zamiast używać cl-positioni nie chcesz przechodzić dwa razy (używając 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)))

To jest dobre nawet dla starszych wersji Emacsa. Ma jednak tę różnicę w zachowaniu, której możesz chcieć lub nie: Działa to również w przypadku samochodów z listy z kropkami. Oznacza to, że poprawnie zwraca pozycję zamiast zgłaszania błędu, dla sexps takich jak(nth-elt 'c '(a b c . d)) .

Jeśli chcesz zawsze zgłaszać błąd związany z niewłaściwą listą, musisz sprawdzić tę sprawę, która wymaga zawsze przejścia do końca listy:

(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)))
Rysował
źródło
2

Okazuje się, że jest to prosta funkcja do pisania, choć może nie być aż tak wydajna:

(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

Oczywiście wolałbym wbudowane rozwiązanie, jeśli takie istnieje.

Dan
źródło