How to find the position of an atom in list

2019-08-29 10:01发布

问题:

I am trying to find the position of an atom in the list.

(position-in-list 'a (a b c d e)) gives 0

(position-in-list 'b (a b c d e) ) gives 1

(position-in-list 'Z(a b c d e) ) gives nil.

I have pasted my code which only returns 1.

(defun position-in-list (letter list) )
( cond
( (null list) nil
)
( (eq (car list) letter) count 
)
( t (position-in-list letter (cdr list)) count)
)
)

( defun count ()
( + 0 1)
)

回答1:

Firstly, the Common Lisp standard library has that already; it's called position.

(position 'a '(a b c d e)) ==> 0
(position 'b '(a b c d e)) ==> 1
(position 'z '(a b c d e)) ==> NIL

In general, things in the standard library are there to be used. (Yes, position gives those outputs. I just ran those through a REPL.)

Secondly, not to sound holier-than-thou or anything, but your parenthesis style just hurts my eyes. Put an opening parenthesis right in front of the first thing in the list, and all closing parens on the same line as the last thing in the list. For example:

(defun hello-world ()
    (format t "Hello World!"))

or

(defun position-in-list (letter list)
  (cond
    ((null list)            nil)
    ((eq (car list) letter) count)
    (t                      (position-in-list letter (cdr list))
                            count)))

(defun count ()
  (+ 0 1))

This might be hard on your eyes [it was for me at first], but it helps you find mistakes more easily.

Thirdly, I don't know what your count function is supposed to be doing, but position-in-list is probably not doing it the way you expect. Try this:

(defun position-in-list (letter list)
  (cond
    ((null list)            nil)
    ((eq (car list) letter) 0)
    (t                      (1+ (position-in-list letter (cdr list))))))

Ultimately, returns NIL if letter is not found in list, or the index if it is. Yes, I know those parens look opaque, but this is how Lisp is written. You'll get used to it.

tl;dr Use position in the standard library; it does what you want.



回答2:

Here is another solution using only recursion:

(defun position-in-list (letter liste)
   (cond
      ((atom liste) nil)
      ((equal letter (car liste)) 0)
      ((position-in-list letter (cdr liste)) (+ 1 (position-in-list letter (cdr liste)))) ) )

((atom liste) nil) = after all the recusion, if the list is empty, it returns nil

((equal letter (car liste)) 0) = if it finds the letter we are looking for, it returns 0 and starts unstacking

((position-in-list letter (cdr liste)) (+ 1 (position-in-list letter (cdr liste)))) = it adds +1 only if have not gone through the whole list already, so only if we have found our letter before then



回答3:

Here is a tail-recursive version in CL:

(defun position-in-list (elt list &key (test #'eql))
  (labels ((pill (tail p)
             (cond ((null tail) nil)
                   ((funcall test elt (first tail)) p)
                   (t (pill (rest tail) (1+ p))))))
    (pill list 0)))

And the equivalent in Scheme (Racket here), which has a nice construct designed for just this (and also eliminates tail calls as part of the language spec of course):

(define (position-in-list elt lst #:test (test eqv?))
  (let pill ([tail lst] [p 0])
    (cond [(null? tail) #f]
          [(test elt (first tail)) p]
          [else (pill (rest tail) (+ p 1))])))