[LISP] Simplify the code

[LISP] Simplify the code

iBlachu
Advocate Advocate
1,267 Views
21 Replies
Message 1 of 22

[LISP] Simplify the code

iBlachu
Advocate
Advocate

Hi,

 

Who can help me simplify the code below, the one that is between the START and END tags.

 

(setq L
	(list
		(list 0 1 2)
		(list 0 1 2)
		(list 0 1 2)
		(list 0 1 2)
	)
)

(setq e 2)
(setq L1 nil)
(foreach
	x
	L
	; START
	(setq t nil)
	(setq i 0)
	(while (< i (length x))
		(if (not (equal i e))
			(setq t (reverse (cons (nth i x) (reverse t))))
		)
		(setq i (1+ i))
	)
	(setq L1 (reverse (cons t (reverse L1))))
	; END
)

(princ L1)
(princ)

 

0 Likes
1,268 Views
21 Replies
Replies (21)
Message 2 of 22

ВeekeeCZ
Consultant
Consultant

First, NEVER use T as a variable. It's a protected symbol for True. (not T) = nil

Message 3 of 22

ВeekeeCZ
Consultant
Consultant

If your goal is 

'(0 1 2) -> '(0 1)

then

(reverse (cdr (reverse '(0 1 2))))

'(0 1)

 

You can use your FOREACH, but you need to build another list (L1). Move convenient is to use a mapcar with anonymous func.

 

(setq L (mapcar '(lambda (x) (reverse (cdr (reverse x)))) L))

0 Likes
Message 4 of 22

iBlachu
Advocate
Advocate

Yes, but note that the variable "e" can be anything and the list L can also have lists of any length, not just 3 elements.

0 Likes
Message 5 of 22

ВeekeeCZ
Consultant
Consultant

So you need just the first 2 items?

 

(list (car x) (cadr x)), or... where's the catch?

 

Edit: Do a more complex example covering all possible cases.

Message 6 of 22

iBlachu
Advocate
Advocate

 

(setq L
	(list
		(list 0 1 2 3 4 5 6 7 8 9)
		(list 0 1 2 3 4 5 6 7 8 9)
		(list 0 1 2 3 4 5 6 7 8 9)
		(list 0 1 2 3 4 5 6 7 8 9)
		(list 0 1 2 3 4 5 6 7 8 9)
	)
)

	(list
		(list 0 1 2 3 4 6 7 8 9)
		(list 0 1 2 3 4 6 7 8 9)
		(list 0 1 2 3 4 6 7 8 9)
		(list 0 1 2 3 4 6 7 8 9)
		(list 0 1 2 3 4 6 7 8 9)
	)

My routine removes the selected item in all sublists. Thus, it can be indicated that we remove e.g. the 5th element (setq e 5) in such a list:

 

0 Likes
Message 7 of 22

ВeekeeCZ
Consultant
Consultant

Why you can't use some routine of those from your last thread?

0 Likes
Message 8 of 22

iBlachu
Advocate
Advocate

I was thinking more about using mapcar or lambda.

0 Likes
Message 9 of 22

ВeekeeCZ
Consultant
Consultant

 

(defun c:test ()
  (setq lst '((0 1 2 3 4 5 6 7 8 9) (0 1 2 3 4 5 6 7 8 9) (0 1 2 3 4 5 6 7 8 9))
	e 5)
  (mapcar '(lambda (sub)
	     (vl-remove-if
	       '(lambda (itm) (= e (vl-position itm sub)))
	       sub))
	  lst)
  )

 

 

... it's the same approach as used HERE ...

Message 10 of 22

ВeekeeCZ
Consultant
Consultant

@iBlachu wrote:

I was thinking more about using mapcar or lambda.


 

Do you understand how those works? Or is it just a black box.... and need some comments? 

0 Likes
Message 11 of 22

ronjonp
Mentor
Mentor

@ВeekeeCZ  Your code will remove all occurrences if they exist:
image.png

Message 12 of 22

john.uhden
Mentor
Mentor

Hey, BeekeeCZ, that was going to be my answer!

In spite of that, it's a good one.

John F. Uhden

0 Likes
Message 13 of 22

john.uhden
Mentor
Mentor

Okay, where's the "dislike" button?

John F. Uhden

0 Likes
Message 14 of 22

ВeekeeCZ
Consultant
Consultant

@ВeekeeCZ wrote:

 

(defun c:test ()
  (setq lst '((0 1 2 3 4 5 6 7 8 9) (0 1 2 3 4 5 6 7 8 9) (0 1 2 3 4 5 6 7 8 9))
	e 5)
  (mapcar '(lambda (sub)
	     (vl-remove-if	       
'(lambda (itm) (= e (vl-position itm sub))) sub)) lst) )

 


 

As @ronjonp well pointed out, this algorithm sacks. Dunno what I was thinking.

We need to include a counter there to match the current index in the list.

 

(defun c:test ()
  (setq lst '((4 5 6 6 6 6 7 8 9 10 11 12 13) (3 4 6 7 8 9) (3 4 6 6 7 8 9))
	edx 2)
  
  (mapcar '(lambda (sub / idx)
	     (setq idx -1)
	     (vl-remove-if
	       '(lambda (itm)
		  (= edx (setq idx (1+ idx))))
	       sub))
	  lst)
  )

 

0 Likes
Message 15 of 22

Kent1Cooper
Consultant
Consultant

This removes a single item by position from a single list:

 

 

(defun RIFL (thelist itemno / prelist); = Remove Item From List
  (if (>= (length thelist) itemno)
    (progn ; then
      (repeat (1- itemno)
        (setq
          prelist (append prelist (list (car thelist)))
          thelist (cdr thelist)
        ); setq
      ); repeat
      (append prelist (cdr thelist))
    ); progn
    (progn ; else
      (prompt "List does not contain that many items.")
      (princ)
    ); progn
  ); if
); defun

 

 

(setq xyz '(1 2 3 4 5 5 5 6 7 8 9))

Command: (rifl xyz 1)
(2 3 4 5 5 5 6 7 8 9)
Command: (rifl xyz 6)
(1 2 3 4 5 5 6 7 8 9) [preserves multiples same as removed item]
Command: (rifl xyz 11)
(1 2 3 4 5 5 5 6 7 8 ) [really no space between 8 & ), but the website makes an emoji of them when together]

Command: (rifl xyz 15)
List does not contain that many items.

 

If applied across a list of sub-lists, presumably you wouldn't want that too-short-a-list message.  What should be done if one of the sub-lists does not contain as many items as the item number to be removed?  Should it simply be left alone?

Kent Cooper, AIA
0 Likes
Message 16 of 22

john.uhden
Mentor
Mentor

Dug this out of my tool box...

;;----------------------------------------------
;; Tony Tanzillo (01-25-02)
(defun cut_nth (lst pos / head)
  (repeat pos
    (setq head (cons (car lst) head)
          lst (cdr lst)
    )
  )
  (append (reverse head) (cdr lst))
)

John F. Uhden

0 Likes
Message 17 of 22

ronjonp
Mentor
Mentor

Another for fun ( assuming a list not storing nil values ) 🙂

 

(defun _removenth (l n / i)
  (setq i -1)
  (vl-remove 'nil
	     (mapcar '(lambda (x)
			(if (/= n (setq i (1+ i)))
			  x
			)
		      )
		     l
	     )
  )
)
(_removenth '(0 1 2 3 3 4 5 6 7 8 9 10 10 10 11) 3)
;; (0 1 2 3 4 5 6 7 8 9 10 10 10 11)

 

 

 

0 Likes
Message 18 of 22

john.uhden
Mentor
Mentor
Pretty tricky @ronjonp
But how can we be sure which 3 you removed? 😜

John F. Uhden

0 Likes
Message 19 of 22

ronjonp
Mentor
Mentor

@john.uhden wrote:
Pretty tricky @ronjonp
But how can we be sure which 3 you removed? 😜

It removed the correct 3 adjacent to 2 😀

0 Likes
Message 20 of 22

john.uhden
Mentor
Mentor
@ronjonp
Okay, prove it! 👺
I had a friend Charlie in high school who dated identical twins, Donna and
Linda.
I'm pretty sure he never really knew which one he was with. But the girls
didn't mind. They were able to share and laugh about their experiences.
I think he ended up marrying Donna, but no one is really sure about that.

John F. Uhden

0 Likes