Pairing list elementes

Discussion of Common Lisp
Post Reply
gardos
Posts: 1
Joined: Wed Jun 22, 2011 8:44 am

Pairing list elementes

Post by gardos » Wed Jun 22, 2011 8:56 am

Hi, because of my ignorance im stuck whit this problem.

I have a list, example:
(1024 -42 42 123 0 6 -1 0 0 -2)
but i need it to look like this:
(1024 . -42) (42 . 123) (0 . 6) (-1 . 0) (0 . -2)

I have already made this function(i need it like this):
(defun make-point (x y) (cons x y))

The problem is that i dont not how to pairing the elements by the make-point function, can you halp me pls?


EDIT: it will be usefull even create two list of alternate elements like:
(1024 42 0 -1 0)
(-42 123 6 0 -2)

I X Code X 1
Posts: 59
Joined: Sun May 29, 2011 8:52 pm
Location: NY
Contact:

Re: Pairing list elementes

Post by I X Code X 1 » Wed Jun 22, 2011 1:22 pm

Okayyyy, this is really ugly and there are probably a million better ways to do this. But I think it does what you want it to. Note: it will only work for an even amount of numbers, but if these are suppose to be coordinates then it should not matter; it will always be an even amount of points.

Code: Select all

(defparameter *y* '())

(defun make-point (list)
  (let ((x (cons (first list) (second list))))
    (setf *y* (push x *y*))
    (if (cddr list)
        (make-point (cddr list))
      (progn (print (reverse *y*))
        (setf *y* '())))))
Okay, I simply made a global variable (could figure out a way to do this without globals if you wanted to) which is going to be the resulting list. Take the cons of the first element and the second element. If the cddr of the list is still a list (not nil/empty), we call the method again. It keeps going until all cons have been pushed into the list. Lastly, I reversed the list because the function push is kind of a LIFO structure in the sense that the last element pushed is in the front of the list, and then I just set *y* back to empty. You can take that part out if you want, I just did it so you can call it again with a new set of elements and the last ones won't be there anymore.

CG-USER(57): (MAKE-POINT '(1 2 3 4 5 6 7 8 9 10))

((1 . 2) (3 . 4) (5 . 6) (7 . 8) (9 . 10))
NIL

CG-USER(61): (MAKE-POINT '(2 3 4 5 6 7))

((2 . 3) (4 . 5) (6 . 7))
NIL

This is what happens if the number of coordinates is odd:

CG-USER(65): (make-point '(1 2 3))

((1 . 2) (3))
NIL


All the coordinates are grouped into a big list, but it would be easy to access them if you needed to. If you really don't want this, you can throw something like this in there and monkey around with the code a bit more. I think it's good how it is now though. Can easily access nested lists inside one big list.

Code: Select all

CG-USER(69): (format t "~a ~a ~a" '(1 . 2) '(3 . 4) '(5 . 6))
(1 . 2) (3 . 4) (5 . 6)
NIL

crabbe
Posts: 2
Joined: Mon Jun 20, 2011 3:42 pm

Re: Pairing list elementes

Post by crabbe » Wed Jun 22, 2011 2:41 pm

Code: Select all

(defparameter *y* '())

    (defun make-point (list)
      (let ((x (cons (first list) (second list))))
        (setf *y* (push x *y*))
        (if (cddr list)
            (make-point (cddr list))
          (progn (print (reverse *y*))
            (setf *y* '())))))
This isn't a lispy-way to do this. Essentially you are collecting the result of the recursion in some external box. The way you want to think about this is that as the call stack unwinds, the result is accumulated:

Code: Select all

* (defun make-point-r (list)
    (cond 
     ((null list) nil) 
     (t (cons (cons (car list) (cadr list)) (make-point-r (cddr list))))))

MAKE-POINT-R
* (make-point-r  '(1 2 3 4 5 6 7 8 9 10))

((1 . 2) (3 . 4) (5 . 6) (7 . 8) (9 . 10))
* (make-point-r  '(1 2 3 4 5 6 7 8 9))

((1 . 2) (3 . 4) (5 . 6) (7 . 8) (9))
In addition to avoiding the external storage, note the lack of #'reverse.

if you care about tail recursion, you can:

Code: Select all

* (defun make-point-t (list &optional (res nil))
    (cond 
     ((null list) res)
     (t (make-point-t (cddr list) (cons (cons  (car list) (cadr list)) res)))))
; 
MAKE-POINT-T
* (make-point-t  '(1 2 3 4 5 6 7 8 9 10))

((9 . 10) (7 . 8) (5 . 6) (3 . 4) (1 . 2))
* (make-point-t  '(1 2 3 4 5 6 7 8 9))

((9) (7 . 8) (5 . 6) (3 . 4) (1 . 2))
But you then might want to reverse it at the end.

I X Code X 1
Posts: 59
Joined: Sun May 29, 2011 8:52 pm
Location: NY
Contact:

Re: Pairing list elementes

Post by I X Code X 1 » Wed Jun 22, 2011 3:13 pm

crabbe wrote:


This isn't a lispy-way to do this. Essentially you are collecting the result of the recursion in some external box. The way you want to think about this is that as the call stack unwinds, the result is accumulated:

Code: Select all

* (defun make-point-r (list)
    (cond 
     ((null list) nil) 
     (t (cons (cons (car list) (cadr list)) (make-point-r (cddr list))))))
Very nice approach at solving this! I am trying to get into the lispy mindset, but it's tough to break my Java roots :roll:

Paul
Posts: 106
Joined: Tue Jun 02, 2009 6:00 am

Re: Pairing list elementes

Post by Paul » Wed Jun 22, 2011 4:44 pm

Ugh.

Code: Select all

(defun make-points (list)
  (loop for x on list by #'cddr collect (cons (first x) (second x))))

I X Code X 1
Posts: 59
Joined: Sun May 29, 2011 8:52 pm
Location: NY
Contact:

Re: Pairing list elementes

Post by I X Code X 1 » Wed Jun 22, 2011 5:11 pm

Paul wrote:Ugh.

Code: Select all

(defun make-points (list)
  (loop for x on list by #'cddr collect (cons (first x) (second x))))
And nice use of the loop, you know.. I was trying to write this before I wrote mine. Just didn't know about the 'by', thanks for sharing that. Will definitely come in handy!

marcoxa
Posts: 85
Joined: Thu Aug 14, 2008 6:31 pm

Re: Pairing list elementes

Post by marcoxa » Wed Jun 22, 2011 10:55 pm

Welllll. I suppose that - being the 23rd - there is no problem giving a way a piece of the assignment

Code: Select all

(defun make-points (l)
    (loop for (x y) on l by #'cddr collect (make-point x y)))
Cheers
Marco Antoniotti

Post Reply