Як отримати номер елемента в списку?


17

Питання: як я можу отримати номер елемента в списку?

nthотримує номер елемента n зі списку:

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

Я хотів би зробити зворотний: отримати номер елемента, заданий елемент:

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

Я, можливо, його пропустив, але чи існує така функція? Як би це зробити?

Відповіді:


22
  1. Ось функція, що входить до Emacs 24.3 та пізніших версій:
(cl-position 2 '(6 7 8 2 3 4)) ;; => 3

(Перед Emacs 24.3 використовуйте функцію positionз бібліотеки cl.el, яка входить до Emacs.)

За допомогою :testключового слова можна вказати функцію порівняння:

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

Загальний посібник з емуляції Lisp

  1. dash.el має функцію, яка може це робити: -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

Це не входить в Emacs, але багато користувачів Emacs вже встановлено (це залежність projectile, flycheckі smartparens, що дає йому тонну покриття).


6

Що ж, якщо ви хочете скочувати свою власну, а не використовувати cl-position, і ви не хочете двічі переходити (використовуючи 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)))

Це добре навіть для старих версій Emacs. Однак він має таку різницю в поведінці, яку ви можете або не хочете: Це працює також для автомобілів пунктирного списку. Тобто, він правильно повертає позицію замість того, щоб викликати помилку, для таких секпсів, як (nth-elt 'c '(a b c . d)).

Якщо ви хочете завжди викликати помилку щодо невідповідного списку, тоді вам потрібно перевірити, чи є випадок, який вимагає завжди переходити до кінця списку:

(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

Виявляється, писати просту функцію, хоча це може бути не так ефективно:

(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

Я б вважав за краще вбудоване рішення, якщо воно існує, звичайно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.