Lisp 列表中所有匹配元素的位置

Lisp 列表中所有匹配元素的位置,lisp,common-lisp,Lisp,Common Lisp,我正试图用公共Lisp编写一个函数,类似于内置的position函数,它返回一个列表,列出与指针匹配的所有元素在haystack中的位置,而不仅仅是第一个元素。我已经提出了一些可能的解决方案(例如,使用位置上的cdr from函数递归搜索下一个元素,并将结果添加到前一个位置),但到目前为止,我提出的任何方法似乎都不是特别优雅 有谁能提出最好的方法来解决这个问题,因为我目前正努力解决这个问题。解决这个问题的显而易见的方法就是依次查看列表中的每个元素,每次进行与针相同的比较时,将其位置收集到输出列表

我正试图用公共Lisp编写一个函数,类似于内置的position函数,它返回一个列表,列出与指针匹配的所有元素在haystack中的位置,而不仅仅是第一个元素。我已经提出了一些可能的解决方案(例如,使用位置上的cdr from函数递归搜索下一个元素,并将结果添加到前一个位置),但到目前为止,我提出的任何方法似乎都不是特别优雅


有谁能提出最好的方法来解决这个问题,因为我目前正努力解决这个问题。

解决这个问题的显而易见的方法就是依次查看列表中的每个元素,每次进行与针相同的比较时,将其位置收集到输出列表中。在这种情况下,获得职位非常容易,因为我们从干草堆开始;我们可以使用变量从0开始计算当前位置

因此,如果我们在一句话中描述完整的算法,我们会说“找到草堆中针的所有位置,对于草堆中的每个元素,以及从0开始的位置,当元素等于针时,收集位置。”

当您想要进行迭代处理时,循环功能基本上是正确的。尽管它的语法很复杂,但你可以把算法的英文描述放在循环体中,这样就可以了

(defun all-positions (needle haystack) (loop for element in haystack and position from 0 when (eql element needle) collect position)) (卸下所有位置(打捆针草垛) (环路 干草堆中的元素 和从0开始的位置 何时(eql元素指针) 收集位置)
如果希望使用递归函数,而不是基于
(循环…
)的函数,可以使用以下内容:

(defun all-positions (needle haystack)
    (labels ((f (n h c r)
                 (if (null h)
                     r
                     (if (eql (car h) n)
                         (f n (cdr h) (1+ c) (cons c r))
                         (f n (cdr h) (1+ c) r))))))
    (reverse (f needle haystack 0 nil)))
这里有另一种(不一定更好)方法

(defun get-positions (needle haystack)
  (let ((result nil))
    (dotimes (i (length haystack))
      (if (eq (nth i haystack) needle)
          (push i result)))
    (nreverse result)))

把这个和一粒盐一起吃(一定要事先装好):

也就是说,它确实具有处理任意序列的优势:

CL-USER> (positions 'x #(x x y y x x y y))
(0 1 4 5)
CL-USER> (positions 5 (list 5.0 -1 5 5.0 -1) :test #'=)
(0 2 3)
CL-USER> (positions #\l "Hello")
(2 3)
CL-USER> (positions 'x #(x x y y x x y y))
(0 1 4 5)
CL-USER> (positions 5 (list 5.0 -1 5 5.0 -1) :test #'=)
(0 2 3)
CL-USER> (positions #\l "Hello")
(2 3)