0

I am trying to find the other element in the nested list when querying the first one. Something like this. (findOther 'a '((a b) (b c) (a d)))--> b and d. I have done this so far: The problem is I only get b.

(defun findOther (elem L)
       (cond (NIL (null L))
        ((eq elem (caar L)) (cdar L))
        ((findOther elem (cdr L)))))

2 Answers 2

1

First some comments on the original code:

(defun findOther (elem L)
  (cond
    ;; NIL is always false, so you *never* end up using this
    ;; case.  You probably want something like ((null l) '()),
    ;; NULL is still pretty common for this, but since you're
    ;; expecting a list, you could use the slighly more
    ;; descriptive ENDP.
    (NIL (null L))
    ;; When you find an element, you immediately return its
    ;; counterpart, and don't collect it and continue on to
    ;; the rest of the list.  It's also easier to read if
    ;; you use more descriptive names like FIRST and SECOND,
    ;; as in ((eq elem (first (first l))) (second (first l))).
    ;; It's worth noting that unless you have a specific reason
    ;; to use EQ, you might want to use EQL, which is the
    ;; default comparison in most CL functions.
    ((eq elem (caar L)) (cdar L))
    ;; Else, you continue to the rest of the list.  In my
    ;; opinion, REST would be more decriptive than CDR here,
    ;; but recursing and returning the value *is* what you
    ;; want to do here.
    ((findOther elem (cdr L)))))

Taking some of those into consideration, we could do something like this:

(defun others (element list)
  (cond
    ((endp list) '())
    ((eql element (first (first list)))
     (list* (second (first list))
            (others element (rest list))))
    ((others element (rest list)))))

All that said, the functions in the standard library would make this much easier. E.g. using mapcan:

(defun others (element list)
  (mapcan (lambda (sublist)
            (when (eql (first sublist) element)
              (rest sublist)))
          list))

(others 'a '((a b) (b c) (a d)))
;=> (B D)
Sign up to request clarification or add additional context in comments.

3 Comments

While using the return value of the test-form in a cond-clause is possible, I'd rather see an explicit t for the default case test-form.
I think this can be done even easier by composing cadr and assoc.
@SamuelEdwinWard OP wants all the matches, though, not just the first one. assoc would only get the first.
0

I am not sure if you are looking for pair of two elements or may be more elements in list as well. Just in case you have more elements and you want all of them as well and also of some of them are not really pairs,

(defun pair-of (elem lis)
 (let ((temp nil))
  (cond
   ((and (listp lis) (not (null lis)))
    (mapcar
     #'(lambda (x)
        (cond
         ((and (listp x) (not (null x)) (eql elem (car x)))
          (push (cdr x) temp))))
     lis)))
  (nreverse temp)))

USAGE:(pair-of 'a '((a b) (b c) (a d w) 1))

OUTPUT: ((B) (D W))

But in case you want them combined in one list, (reduce #'append (pair-of 'a '((a s) (a 3 8) (2 5 1))):initial-value '()) => (S 3 8)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.