Remove items from list?

Q&A's, tips, howto's
Locked
cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Remove items from list?

Post by cormullion »

Is it possible to remove items from nested lists just using set-ref-all?

Code: Select all

(set 'planets '(("Mercury"
      (p-name "Mercury")
      (diameter 0.382)
      (mass 0.06)
      (radius 0.387)
      (period 0.241)
      (incline 7)
      (eccentricity 0.206)
      (rotation 58.6)
      (moons 0))
  ("Venus"
      (p-name "Venus")
      (diameter 0.949)
      (mass 0.82)
      (radius 0.72)
      (period 0.615)
      (incline 3.39)
      (eccentricity 0.0068)
      (rotation -243)
      (moons 0))
      ))
      
(set-ref-all '(p-name *) planets '() match)
;->
  (
    ("Mercury" 
      () 
      (diameter 0.382) 
      (mass 0.06) 
      (radius 0.387) 
      (period 0.241) 
      (incline  7)  
      (eccentricity 0.206)  
      (rotation 58.6)  
      (moons 0))  
    ("Venus" 
      () 
      (diameter 0.949) 
      (mass 0.82) 
      (radius 0.72) 
      (period 0.615) 
      (incline 3.39)  
      (eccentricity 0.0068)  
      (rotation -243)  
      (moons 0)))
The empty lists are close but not perfect... :(

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Re: Remove items from list?

Post by Lutz »

Code: Select all

(dolist (item (ref-all '(p-name *) planets match)) 
	(pop planets item))
now planets has all '(p-name *) removed:

Code: Select all

(("Mercury" 
  (diameter 0.382) 
  (mass 0.06) 
  (radius 0.387) 
  (period 0.241) 
  (incline 7) 
  (eccentricity 0.206) 
  (rotation 58.6) 
  (moons 0)) 
 ("Venus" 
  (diameter 0.949) 
  (mass 0.82) 
  (radius 0.72) 
  (period 0.615) 
  (incline 3.39) 
  (eccentricity 0.0068) 
  (rotation -243) 
  (moons 0)))

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Re: Remove items from list?

Post by cormullion »

I didn't see an obvious way for set-ref-all to do it, so I'm quite glad I didn't overlook anything obvious...

But I think your suggestion fails on nested lists - because the list is changed by pop, then subsequent changes cause a list out of bounds error? Or am I mistaken? (I'm processing SXML - the example I gave was a bad choice!)

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Re: Remove items from list?

Post by Lutz »

pop in reverse order:

Code: Select all

(dolist (item (reverse (ref-all '(p-name *) planets match)))
   (pop planets item))

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Re: Remove items from list?

Post by Lutz »

.. just wanted to expand on this. The family 'ref' functions always looks for matches going through a list from left to right, depth first. This means, that the removal of any matched expression found only affects indexes of items following, regardless of nesting, even if matches contain matches in a recursive fashion. Consider this:

Code: Select all

> (set 'theList '(a (b) (b (b 2) (b (b 3) (b 4)))))
(a (b) (b (b 2) (b (b 3) (b 4))))
> (ref-all '(b *) theList match)
((1) (2) (2 1) (2 2) (2 2 1) (2 2 2))
> (pop theList '(2 2 2))
(b 4)
> (pop theList '(2 2 1))
(b 3)
> (pop theList '(2 2))
(b)
> (pop theList '(2 1))
(b 2)
> (pop theList '(2))
(b)
> (pop theList '(1))
(b)
> theList
(a)
> 
vice versa you can construct the original list from all the items popped and the index vector:

Code: Select all

(set 'theList '(a (b) (b (b 2) (b (b 3) (b 4)))))

; the list of the index vectors
(set 'indexList (ref-all '(b *) theList match))

; the list of all popped items
(set 'popped (map (curry pop theList) (reverse (copy indexList))))

; after popping out all matches
theList ;=> (a)

; reconstruct the list from popped items starting with residual list
(map (fn (m i) (push m theList i)) (reverse (copy popped)) indexList)

theList ;=> (a (b) (b (b 2) (b (b 3) (b 4))))
Note, that 'reverse' has to be made non-destructive using 'copy'.

Locked