Как получить номер элемента в списке?


16

Q: как мне получить номер элемента в списке?

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

Руководство по эмуляции Emacs Common 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.