Association in Common Lisp - lisp

There's a structure of the following format:
(setq dist '(((1 1) 1)
((0 2) 3)
((1 2) 1)
((2 3) 3)
((3 5) 4)))
Is there any function which, if I call
(myf '(0 2))
could give me
3
or
((0 2) 3)
Something like a reverse assoc

I fail to see why this would be called a reverse ASSOC.
(assoc '(0 2) dist :test #'equal)
> ((0 2) 3)
It looks like ASSOC works fine, provided you change the test function, so that lists used as keys are correctly tested.

Related

How to do stored in place adjoin in lisp

I'm new to lisp and I'm looking for a function to do a stored in place adjoin, is there any? i found the pushnew macro but it seems to work on items not lists.
(pushnew '((1)) '((1) (1 2) (1 2 3)))
(pushnew '(1) lst) => ((1) (1) (1 2) (1 2 3))
PUSHNEW is the modifying version of ADJOIN. You need to use the proper :TEST argument for comparing the kind of elements the list contains (such as #'EQUAL for lists).
CL-USER> (defparameter *list* (list (list 1)
(list 1 2)
(list 1 2 3)))
*LIST*
CL-USER> (adjoin '(1) *list*) ; Adds
((1) (1) (1 2) (1 2 3))
CL-USER> (adjoin '(1) *list* :test #'equal) ; Doesn't add
((1) (1 2) (1 2 3))
CL-USER> (pushnew '(1) *list*) ; Pushes
((1) (1) (1 2) (1 2 3))
CL-USER> *list*
((1) (1) (1 2) (1 2 3))
CL-USER> (pushnew '(1) *list* :test #'equal) ; Doesn't push
((1) (1) (1 2) (1 2 3))

Find and remove a list item based on the item's third element

I need to find and return the first item in a list when that item's third element matches a value passed into the function. I then need that item to be permanently removed from the list.
I have written this function to do it and am wondering if there are any built-in functions that might accomplish the same without this fairly messy implementation:
(defun find-remove-third (x)
(let ((item (first (member x *test-list* :key #'third))))
(setf *test-list* (remove item *test-list* :test #'equal))
item))
Operation:
CL-USER> *test-list*
((1 2 3) (2 3 4) (3 4 5) (4 4 4) (5 4 3) (6 5 4) (2 2 2))
CL-USER> (find-remove-third 4)
(2 3 4)
CL-USER> *test-list*
((1 2 3) (3 4 5) (4 4 4) (5 4 3) (6 5 4) (2 2 2))
CL-USER> (find-remove-third 4)
(4 4 4)
CL-USER> *test-list*
((1 2 3) (3 4 5) (5 4 3) (6 5 4) (2 2 2))
For example pop mutates and returns from a list, though is more limited, but I'm wondering if anything more elegant than my function above might be possible, or if this implementation is normal and idiomatic?
Your implementation scans the list twice, so it is suboptimal.
I don't think you can write what you need without an explicit loop (or, equivalently, recursion):
(defun pop-from-list (object list &key (key #'identity) (test #'eql) kept)
"Like `remove', but return the object removed as the second value."
(let ((1st (car list)))
(if (funcall test object 1st)
(values (revappend kept (rest list))
1st)
(pop-from-list object (rest list) :key key :test test
:kept (cons 1st kept)))))
Now you can define your function like this:
(defun find-remove-third (x)
(multiple-value-bind (list object)
(pop-from-list x *test-list* :key #'third)
(setq *test-list* list)
object))
Edit - Deleting this doesn't seem right so I'll leave it up, but as noted by #sds and #WillNess in the comments, this has serious issues.
Here's a destructive version which only scans the list once. It has the potential benefit that you don't have to hardcode the name of the list you're operating on.
CL-USER> (defun find&remove (list obj &key (key #'identity) (test #'eql))
(loop with last = nil
for cons on list
when (funcall test obj (funcall key (first cons))) do
(progn (setf (rest last) (rest cons))
(return (first cons)))
do (setf last cons)))
CL-USER> (defvar test-list (list (list 1 2 3)
(list 3 4 5)
(list 5 6 7)
(list 8 9 10)))
CL-USER> (find&remove test-list 5 :key #'third)
(3 4 5)
CL-USER> test-list
((1 2 3) (5 6 7) (8 9 10))
CL-USER> (find&remove test-list 7 :key #'third)
(5 6 7)
CL-USER> test-list
((1 2 3) (8 9 10))
The key is to traverse the list by cons cell rather than by item (loop for ... on rather than loop for ... in) and keep a pointer to the parts of the list we've already looked at (last). Then, when we find what we're looking for, we connect the cdr of what we'd already seen to the next cons (so now the list omits the "hit") and finally return the result.

how to test whether one list is a member of another

Lets say I have two lists, ((1 2 3)) and (((1 2 3)) ((4 5))). I want to be able to tell if the first list is a member of the second list. I have tried to use subsetp, but it does not return true for this query. How can I accomplish this?
As Rainer Joswig mentioned in the comments, you're not checking for subsets, but for members, which you can do using the aptly named member function. Member returns a generalized boolean, i.e., nil for false, and something, not necessarily t, non-nil for true. Specifically, if an element is a member of the list, member returns the tail of the list whose first element is the element.
CL-USER> (member 3 '(1 2 3 4 5))
(3 4 5)
CL-USER> (member 7 '(1 2 3 4 5))
NIL
Of course, when checking membership in a list, there's a question of how to compare the given item with the elements of the list. Member's default comparison is eql, which works on things like numbers, as shown in the example above. For your case, however, you probably want to test with equal, since ((1 2 3)) might not be the same object as the first element of (((1 2 3)) ((4 5))):
CL-USER> (member '((1 2 3)) '(((1 2 3)) ((4 5))))
NIL
CL-USER> (member '((1 2 3)) '(((1 2 3)) ((4 5))) :test 'equal)
(((1 2 3)) ((4 5)))
CL-USER> (member '((4 5)) '(((1 2 3)) ((4 5))) :test 'equal)
(((4 5)))
CL-USER> (member '((1 2 4)) '(((1 2 3)) ((4 5))) :test 'equal)
NIL
If you want to have lists as elements of your sets for subsetp, you have to change the value of the :test keyword.
CL-USER 1 > (subsetp '(1 2 3) '(1 2 3 4 5))
T
CL-USER 2 > (subsetp '((1) (2) (3)) '((1) (2) (3) (4) (5)))
NIL
The first one gives T, the second one gives NIL. Why? Because equality is checked with #'eql which works for identical objects or numbers of the same value and of same type. Since two lists must not be identical objects, (eql '(1) '(1)) gives NIL. (That may depend on your CL implementation.) If you want to compare a tree of conses, tree-equal can help you.
CL-USER 3 > (subsetp '((1) (2) (3)) '((1) (2) (3) (4) (5)) :test #'tree-equal)
T
I don't understand the structure of the sets you gave as example completely, but I hope this helps.

Lisp Recreating a Temporary Variable

I'm having a bit of trouble with Lisp. What i'm attempting to do, is keep track of the amount of times a number appears in x number of lists. However, running this over and over again, lisp isn't recreating the variable, but using the ending value from the last time I called the function. So I'm wondering how can I get past the 'binding' powers of let?
So, I've got some list like this
(((8 7) (3)) ((8 3) (2)) ((7 3) (6)) ((7 2) (8)) ((6 7) (4 1))
((6 6) (4 1)) ((6 2) (2)) ((5 6) (3)) ((5 3) (8 3)) ((4 6) (4))
((4 4) (6)) ((4 1) (7)) ((3 7) (5 3)) ((3 4) (1)) ((3 3) (3)) ((3 1) (9))
((2 7) (7)) ((2 5) (2)) ((2 2) (5 2)) ((1 7) (1)) ((1 6) (6 1))
((1 1) (2 1)) ((1 0) (3)) ((0 7) (8 1)) ((0 5) (6)) ((0 3) (9 6))
((0 1) (1)))
Then I'm calling some function like this, (declaring var here doesn't seem to do anything, past the initial function call)... I guess some kind of binding from let.
(defun counter (possibleValues)
(let ((var '(0 0 0 0 0 0 0 0 0 0)))
(loop for i from 0 to (list-length possibleValues) do
(loop for j in (cdr (nth i possibleValues)) do
(loop for k in j do
(incf (nth k var)))))
var))
So I can run my list through the function and get something like
(0 8 5 6 3 2 5 2 3 2)
Each position referring to the number found in the list. So the value 8 would refer to how many times 1 was found in all the lists (i'm considering the second list only). Now the problem.... run it twice and...
(0 16 10 12 6 4 10 4 6 4)
I was using an associative list earlier, but in trying to figure this out and keep things simple, i'm now using a list. I guess another question I have is, how can I create associative list elements on the fly? I don't like declaring 'var' like that, but I'm just trying to get around 'let' for the moment. I haven't had much luck with 'setq' or 'setf' either....
Thanks in advance for your help!
Change the initialization form for VAR to be an expression that creates new lists, such as (make-list 10 :initial-element 0) or even (list 0 0 0 0 0 0 0 0 0 0).
Basically, do not ever use quoted objects if you have intentions on modifying them, as the consequences are undefined if you do. In fact, evaluating that function definition gives a warning about that:
; in: LAMBDA NIL
; (INCF (NTH K VAR))
; --> LET*
; ==>
; (SB-KERNEL:%SETNTH #:TMP5 #:TMP4 #:NEW3)
;
; caught WARNING:
; Destructive function SB-KERNEL:%SETNTH called on constant data.
; See also:
; The ANSI Standard, Special Operator QUOTE
; The ANSI Standard, Section 3.2.2.3
;
; compilation unit finished
; caught 1 WARNING condition

Common Lisp: Why not the array literal evaluate arguments?

Why is it that the Common Lisp array syntax is not evaluating its arguments:
(let ((a 1)) #2A((a 2) (3 4)))
=> #2A((A 2) (3 4))
I would have guessed it was #2A((1 2) (3 4)). Is this because A is not available at reader time?
In short, yes.
#2A((A 2) (3 4)) is not an abbreviation ("syntactic sugar") for (make-array '(2 2) :initial-contents (list (list a 2) (list 3 4))). If anything, it could be rationalized as (make-array '(2 2) :initial-contents (quote ((A 2) (3 4)))), but this would be a bit misleading as the array construction already happens at read-time.