TheSwamp
Code Red => AutoLISP (Vanilla / Visual) => Topic started by: JohnK on July 30, 2004, 12:11:18 PM
-
Alright you guys, you know the rules! Get to it!
I want a tool to insert an item into a list at a specific postion (zero based).
(<tool name here> [item] [position])
Example:
given a list: (1 2 4 5 6 7)
(insert@ '(1 2 4 5 6 7) 3 2)
-> (1 2 3 4 5 6 7)
And ....GO!
-
OBTW, I found one of Reni's posts that has a util like this a few days ago and i thought it was a good idea for a challenge.
...And since im using Crappystation today i will post that procedure a bit later and maybe get to writing one of my own at lunch.
-
Alright you guys, you know the rules! Get to it!
I want a tool to insert an item into a list at a specific postion (zero based).
(<tool name here> [item] [position])
Example:
given a list: (1 2 4 5 6 7)
(insert@ '(1 2 4 5 6 7) 3 2)
-> (1 2 3 4 5 6 7)
And ....GO!
Certainly not optimized, but here's my quick stab at it:
(defun ListInsert ( lst item position / i index1 index2 )
(cond
( (< position 1) (cons item lst))
( (< (length lst) position) (append lst (list item)))
( (setq i -1)
(append
(reverse
(mapcar 'cdr
(member
(assoc (1- position)
(setq index2
(reverse
(setq index1
(mapcar
'(lambda (x) (cons (setq i (1+ i)) x))
lst
)
)
)
)
)
index2
)
)
)
(list item)
(mapcar 'cdr (member (assoc position index1) index1))
)
)
)
)
(listinsert '(1 2 4 5 6 7) 3 2) ==> (1 2 3 4 5 6 7)
Cheers,
M.
-
(defun insert@ (lst itm pos / nlst idx)
(setq nlst '()
idx -1)
(while (< (setq idx (1+ idx)) (length lst))
(if (= idx pos)
(setq nlst (cons (nth idx lst) (cons itm nlst)))
(setq nlst (cons (nth idx lst) nlst))
)
)
(reverse nlst)
)
-
(defun insert@ (lst itm pos / nlst idx)
(setq nlst '()
idx -1)
(while (< (setq idx (1+ idx)) (length lst))
(if (= idx pos)
(setq nlst (cons (nth idx lst) (cons itm nlst)))
(setq nlst (cons (nth idx lst) nlst))
)
)
(reverse nlst)
)
Hi CAB,
It is tempting to go that route, because it's less code, but you would be surprised at the difference in performance. Try this:
(setq lst '(0 0))
(repeat 15 (setq lst (append lst lst)))
Now bench the execution time of
(ListInsert lst 1 1)
versus
(Insert@ lst 1 1)
Actually, you don't even neeed to bench it, the difference is dramatic enough you don't need execution times to see the difference (which is the order of about 500). Obviously on short lists the performance difference is negligable, but I frequently deal with huge lists, thus the performance concern.
Havin' fun,
M
-
w00t! discussion!
CAB, that is the same thing i was thinking.
MP, good point.
As i promised, here is Reni U.'s procedure.
;;; Insert atom in list at pos n
(defun insert (lst x n)
(cond
((zerop n) (cons x lst))
(T (cons (car lst) (insert (cdr lst) x (1- n))))))
Now taking into concideration MP's big list point and the fact that this lil procedure uses a recursive method, should there be a concern?
-
WOW, 500!
I had no idea there was that much difference.
-
OK, How about this one :shock:
(defun insert@ (lst itm pos / ptr)
(setq ptr (nth pos lst))
(append (reverse(cdr(member ptr (reverse lst)))) (list itm) (member ptr lst))
)
-
I think it looks perty CAB. (Does that count?)
What no one else has a say 'cept MP CAB and Reni?!
-
Here are my timer test.
(startTimer)
;;;=============================================================
(repeat 1000
(Insert '(1 2 4 5 6 7) 3 2)
)
;;;=============================================================
(endTimer "instest")
==============================
New insert@
Timed instest: 0.009978
Timed instest: 0.009978
Timed instest: 0.009978
==============================
Old insert@
Timed instest: 0.029974
Timed instest: 0.029974
Timed instest: 0.029974
Timed instest: 0.029974
==============================
M's ListInsert Routine
Timed instest: 0.059988
Timed instest: 0.059988
Timed instest: 0.059988
==============================
Old insert@ again
Timed instest: 0.030014
Timed instest: 0.019996
Timed instest: 0.029974
Timed instest: 0.019996
Timed instest: 0.029974
==============================
New insert@ again
Timed instest: 0.020036
Timed instest: 0.010018
Timed instest: 0.009978
Timed instest: 0.009978
Timed instest: 0.019996
Timed instest: 0.019996
Timed instest: 0.010018
Timed instest: 0.010018
Timed instest: 0.009978
==============================
M's ListInsert Routine again
Timed instest: 0.059988
Timed instest: 0.059988
Timed instest: 0.070006
Timed instest: 0.059988
Timed instest: 0.070006
Timed instest: 0.060028
Timed instest: 0.059988
Timed instest: 0.060028
Timed instest: 0.060993
Timed instest: 0.070006
==============================
Insert by Reni U.
Timed instest: 0.009978
Timed instest: 0.010018
Timed instest: 0.010018
Timed instest: 0.010018
Timed instest: 0.009978
Timed instest: 0.009978
Timed instest: 0.009978
Timed instest: 0.010018
Timed instest: 0.010018
Timed instest: 0.009978
-
I think you will find that your new function only works as long as every single item in the existing list is unique.
The performance of Reine's function progressivley degrades the closer the replacement position is to the far end of the list (when the list is of significant length).
Also, Reine's is limitied by the stack (because it recurses). Try Reine's function on the list I created above and insert at the second last position.
*Kaboom*.
:)
-
MP, Thats kinda my point. What makes Mapcar free form that restraint since it too is recursive by nature. ...well for that matter Lisp is recursive isnt it!?
-
I think you will find that your new function only works as long as every single item in the existing list is unique.
SHOOT, BACK TO THE DRAWING BOARD. :)
-
MP, That's kinda my point. What makes Mapcar free form that restraint since it too is recursive by nature. ...well for that matter Lisp is recursive isn't it!?
Is mapcar recursive? I don't know that it is or isn't, but I'm leaning towards not. If it were recursive it would be subject to stack failures, and I've never seen a mapcar call produce a stack failure. That doesn't mean it can't happen, just that I've never seen it happen in 15 years of LISP programming.
LISP comfortably supports recursive calls (the first language to support recursion if I'm not mistaken), but I wouldn't say "it's recursive". LIST based for sure, and some LISP processing is recursive, but in my way of thinking a blanket "is recursive" statement doesn't fit. However, this is another unqualified opinion.
Having said that, I'm just a hack -- some real bit head with fully functioning grey matter will have to step up to the plate because I don't know the internal workings of the LISP engine.
Cheers. :)
-
I'd do it much like CAB's first INSERT@ function
(defun insert@ (lst item n / a nlst)
(setq a 0)
(while lst
(and (= a n) (setq nlst (cons item nlst)))
(setq nlst (cons (car lst) nlst)
lst (cdr lst)
a (1+ a))
)
(reverse nlst)
)
(setq alst '(A B C D E F G))
(insert@ alst '(X Y Z) 3)
(A B C (X Y Z) D E F G)
-
Here is Stig's run at the timer
Stig's Insert@
Timed instest: 0.019996
Timed instest: 0.029974
Timed instest: 0.029974
Timed instest: 0.019996
Timed instest: 0.019996
Timed instest: 0.030014
Timed instest: 0.019996
Timed instest: 0.019996
Timed instest: 0.019996
Timed instest: 0.029974
Timed instest: 0.030014
Timed instest: 0.019996
Timed instest: 0.019996
-
Mapcar is recursive by nature. (Im almost postitve!) Here is an entry from Structure and Interpretation of Computer Programs (http://mitpress.mit.edu/sicp/full-text/book/book.html)
Mapping over lists
One extremely useful operation is to apply some transformation to each element in a list and generate the list of results. For instance, the following procedure scales each number in a list by a given factor:
(define (scale-list items factor)
(if (null? items)
nil
(cons (* (car items) factor)
(scale-list (cdr items) factor))))
(scale-list (list 1 2 3 4 5) 10)
(10 20 30 40 50)
We can abstract this general idea and capture it as a common pattern expressed as a higher-order procedure, just as in section 1.3. The higher-order procedure here is called map. Map takes as arguments a procedure of one argument and a list, and returns a list of the results produced by applying the procedure to each element in the list:12
(define (map proc items)
(if (null? items)
nil
(cons (proc (car items))
(map proc (cdr items)))))
(map abs (list -10 2.5 -11.6 17))
(10 2.5 11.6 17)
This doesnt prove that it is but since Autolisp is alot like scheme i would assume that "map-car" is recursive. Besides the name makes sence; Map a procedure to the first in the list.
But, we are doing nothing but splitting hairs here. Recursive is recursive. Seeing as recursion is a basic principle for problem solving in programing i would suspect that 90% of our functions are in fact recursive by nature.
...maybe its not subject to stack failures because of built in error traping in the intripriter. huh?
Gawd i love these discussions! They get me thinking!
-
It doesn't say anything about mapcar, but here's something kind of interesting that explains where car and cdr came from:
http://www-formal.stanford.edu/jmc/history/lisp/lisp.html
-
What dosent say anything about mapcar?
Yes that is a very good reference to have. I had another (similar) one at one time, ill have to look arround for it when i get some time. Good find!
Heres the almost exact same reference to what CAR & CDR stand for in the Struct&Intrip book. LINK (http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-14.html#footnote_Temp_133)
-
Had some time to play with this today. So here's my two cents worth, if anyone is still watching. Not sure if this is any faster.
(defun insert@ (lst item pos / tmp)
;; Insert item into lst at pos, zero based
(repeat pos
(setq tmp (cons (car lst) tmp)
lst (cdr lst)
)
)
(append (reverse tmp) (list item) lst)
)
(setq alst '(A B C (1 2 3) D E F G))
(length alst) -> 8
(insert@ alst '(X Y Z) 0) -> ((X Y Z) A B C (1 2 3) D E F G)
(insert@ alst '(X Y Z) 3) -> (A B C (X Y Z) (1 2 3) D E F G)
(insert@ alst '(X Y Z) 8) -> (A B C (1 2 3) D E F G (X Y Z))
(insert@ alst '(X Y Z) 10) -> (A B C (1 2 3) D E F G nil nil (X Y Z))
In the last example you can see that the value of the argument 'Pos was larger then the number of positions existing in the argument 'Lst. Hence, the function padded the result with nils in order to put Iitem at 'Pos.
I'm not sure if that's the best way to handle this "position overflow" condition. Perhaps the function should simply return nil under this condition.
Comments anyone?
Regards,
Steve Doman
-
Nice Job Steve.
It's pritty quick.
Timed instest: 0.019996
Timed instest: 0.020036
Timed instest: 0.019996
Timed instest: 0.019996
Timed instest: 0.009978
Timed instest: 0.020036
Timed instest: 0.009978
-
Thanks for time testing CAB.
While you where doing that, I was editing my previous post with a comment about overflow. (Sorry, probably should have created a new post)
What do you think about the result of the function when given a "postiion overflow" condition?
-
Did not have much of a change.
Timed instest: 0.019996
Timed instest: 0.019996
Timed instest: 0.010018
Timed instest: 0.009978
Timed instest: 0.010018
Timed instest: 0.019996
Timed instest: 0.009978
Timed instest: 0.009978
Timed instest: 0.019996
Timed instest: 0.010018
Timed instest: 0.020036
Timed instest: 0.019996
One thing I noticed about Stig's routine.
There were a few .03 which I did not see in other runs.
I ran Stig's again and they reappeared. Something going on there?
-
Cab,
I didn't change my code, I added a comment to the end of my first post :)
Sorry 'bout all the confusion.
Regading Stig's function, perhaps the timer results are larger when his function is tested on very long lists, since it keeps iterating to the end of the list, rather than stopping at the target postion.
-
Steve, good point about stopping and simply append the remaining list. Nice work!
-
Thanks a billion Stig!