Remove subitem from association 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 subitem from association list

Post by cormullion »

Given an association list:

Code: Select all

(set 'al '(
  ("A" 123 "fred" 2)
  ("B" 234 "jim" 3)
  ("C" 345 "arthur" 4)
  ("D" 456 "dave" 5)))
how would I remove the "fred" "jim" "arthur" and "dave" strings? In fact, I don't want to remove them by referring to their content, but by specifying index 2. It doesn't seem to be as easy as it could be. (Or is it?!)

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

Post by Lutz »

There are two ways to do this. The first method pops from each sub-list and is only possible since v.10.0:

Code: Select all

; remove the element at offset 2 in each sublist
(dotimes (i (length al))
	(pop (al i) 2))

al => (("A" 123 2) ("B" 234 3) ("C" 345 4) ("D" 456 5))
The second way treats 'al' as one nested list using two indexes to address the element to be popped from 'al':

Code: Select all

; remove at i 2 of al
(dotimes (i (length al))
  (pop al i 2))

; remove at (list i 2) of al
(dotimes (i (length al))
  (pop al (list i 2)))
The second time the indexes are in a vector, similar to what 'ref' would return in

Code: Select all

(ref "fred" al) => (0 2)

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

Post by Lutz »

... and yet another method addressing the sublists as associations:

Code: Select all

(pop (assoc "A" al) 2) => "fred"

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

Post by cormullion »

cool. thanks! I had been trying replace and set-ref-all - to avoid looping ...

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

Post by Lutz »

avoid looping ...
you could use 'replace' with 'match':

Code: Select all

(replace '(*) al (append (0 2 $it) (-1 $it)) match)

al => (("A" 123 2) ("B" 234 3) ("C" 345 4) ("D" 456 5))
you could do similar with 'set-ref-all' but I suspect that this is faster. The match expression will match every top-level list in 'al', which are the sub-lists in $it. $it is not writable, so we have to construct the new sublist appending slices.

Likewise you could do:

Code: Select all

(set 'al (map (fn (e) (append (0 2 e) (-1 e))) al))
but I guess your were looking for an in-place replacement.

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

Post by cormullion »

Yes, they all work! I like the powerful single line style. The more you look, the more you find:

Code: Select all

(replace '(*) al (list (select $it '(0 1 3))) match)
thanks!

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

Post by Lutz »

... and you don't need 'list' and the selection indexes don't need to be in a list (but they can be, if you wish):

Code: Select all

(replace '(*) al (select $it 0 1 3) match)
so that is probably the shortest solution, we can come up with.

newdep
Posts: 2038
Joined: Mon Feb 23, 2004 7:40 pm
Location: Netherlands

Post by newdep »

Yes true you have to look because its not that obvious actualy..

something that I would use instantly is a combination of 'map
together with 'pop.. but its not going to work..

but this is..

Code: Select all

(map (fn(x) (replace (x 2) x)) al) 
is a short solution and returns the result but its a non-destructive solution..
-- (define? (Cornflakes))

newdep
Posts: 2038
Joined: Mon Feb 23, 2004 7:40 pm
Location: Netherlands

Post by newdep »

oke oke and there is the good old loop (hello python)

Code: Select all

(for (x 0 (dec (length al))) (pop (al x) 2) )
probably the fastest..
-- (define? (Cornflakes))

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

Post by Lutz »

but we had a better one like this already (first solution in this thread):

Code: Select all

(dotimes (i (length al))
   (pop (al i) 2))

Locked