TheSwamp
Code Red => AutoLISP (Vanilla / Visual) => Topic started by: hendie on March 22, 2007, 09:49:31 AM
-
and now for my second post of the day (it's not been good so far !)
I have a list and each item in the list is composed of a number of elements, for example
BlockID Location Item Description SomethingElse
I need to sort this list by the Location THEN by the item
I've been using
(setq ListSorted2
(vl-sort
Summarylist
'(lambda (s1 s2)
(< (cadr s1) (cadr s2))
)
)
)
which will sort the list on one of the elements, but I then need it sorted on another sub-element without losing main order, if you get my drift.
example list
Block3 GroundC XYZ BlahBlah xxxx
Block1 GroundB RST BlahBlah xxxx
Block5 GroundA ABC BlahBlah xxxx
Block2 GroundA DEF BlahBlah xxxx
I need to return that list sorted as
Block5 GroundA ABC BlahBlah xxxx
Block2 GroundA DEF BlahBlah xxxx
Block1 GroundB RST BlahBlah xxxx
Block3 GroundC XYZ BlahBlah xxxx
-
Found this in my doc's folder. I think it could be of use
To expand on the example Vladimir gave briefly:
Given a list:
(setq lst '((2 . "A") (1 . "B") (4 . "D") (3 . "C") (5 . "E")))
To sort this list, using vla-sort, by the ALPHA we can use something like:
Command: (val-sort lst (lambda (x) (ascii (cdr x))))
((2 . "A") (1 . "B") (3 . "C") (4 . "D") (5 . "E"))
to sort this list by NUM we can use something like:
Command: (val-sort lst (lambda (x) (abs (car x))))
((1 . "B") (2 . "A") (3 . "C") (4 . "D") (5 . "E"))
From: Nesterovsky, Vladimir <vnestr@netvision.net.il>
Subject: Re: Sort a list numerically by first elements
Newsgroups: autodesk.autocad.customization
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Message-Id: <1113388@discussion.autodesk.com>
References: <1113385@discussion.autodesk.com>
Date: Thu, 25 Oct 2001 21:17:27 +0000
If you have a complex and potentially "heavy" key-retrieval
function (admittedly, not your simple case of CAR here),
then you better sort by value instead of by comparison:
(defun val-sort (lst valfun)
(mapcar 'cdr
(vl-sort
(mapcar '(lambda(x) (cons (valfun x) x)) lst)
'(lambda(a b)(< (car a) (car b))))))
For example, if you'd want to sort your list by hex-value of
the strings, you'd make a call
(val-sort lst (lambda (x) (hex-val (cdr x))))
HTH
--
Have fun, :-)
Vlad http://vnestr.tripod.com/
(define (average . args)
(if args (/ (apply '+ args) (length args))))
Jason Piercey <Jason@AtrEng.com> wrote in message
news:0E4759205497EDD0BD568DEBB6B9AE4F@in.WebX.maYIadrTaRb...
> I have a list of dotted pairs, the first element being an integer, the
> second being a string.
>
> ((2 . "A") (1 . "B") (3 . "C"))
>
> How would I go about sorting this list numerically by the first element o=
f
> each pair, so the return value is
>
> ((1 . "B") (2 . "A") (3 . "C"))
>
> I think I need to use mapcar and lambda, I'm just not versed well enough
> with those functions to figure it out.
>
> Thanks for you input.
>
> -Jason
>
>
>
>
-
Not the simplest method, but an effective one, would be to place all of the items of the same "Location" into one list, then sort them according to "Item", then join the list together again ...
;set our counter to 1
(setq ndx 1)
(while (>(length mylist) 0) ;while we have a list to work with
(set (read (strcat "*TEMP" (rtos ndx 2 0))) <all matching "location" items>) ;grab all of the matching locations - you need to edit this to make a list and extract as needed
(foreach n (eval (read (strcat "*TEMP" (rtos ndx 2))))
(setq mylist (vl-remove n mylist));remove the list items from mylist
)
<sort "*TEMPx" by item here>
(setq ndx (1+ ndx))
)
<recombine lists in alphabetical order decrementing ndx back to 1>
-
(SETQ thelist (LIST (LIST "Block3" "GroundC" "XYZ" "BlahBlah" "xxxx")
(LIST "Block1" "GroundB" "RST" "BlahBlah" "xxxx")
(LIST "Block5" "GroundA" "ABC" "BlahBlah" "xxxx")
(LIST "Block2" "GroundA" "DEF" "BlahBlah" "xxxx")
)
)
(SETQ summarylist
(MAPCAR '(LAMBDA (apart)
(LIST (CAR apart)
(VL-PRINC-TO-STRING (CDR apart))
)
)
thelist
)
)
(SETQ listsorted2
(VL-SORT summarylist
'(LAMBDA (s1 s2) (< (CADR s1) (CADR s2)))
)
)
(SETQ summarylist2
(MAPCAR '(LAMBDA (apart)
(CONS (CAR apart) (READ (CADR apart)))
)
listsorted2
)
)
spits out
(("Block5" GROUNDA ABC BLAHBLAH XXXX) ("Block2" GROUNDA DEF BLAHBLAH XXXX) ("Block1" GROUNDB RST BLAHBLAH XXXX) ("Block3" GROUNDC XYZ BLAHBLAH XXXX))
-
Can be so
(setq Summarylist
(list
(list "Block3" "GroundC" "XYZ" "BlahBlah" "xxxx")
(list "Block1" "GroundB" "RST" "BlahBlah" "xxxx")
(list "Block5" "GroundA" "ABC" "BlahBlah" "xxxx")
(list "Block2" "GroundA" "DEF" "BlahBlah" "xxxx")
)
)
(mapcar (function (lambda (x) (nth x Summarylist)))
(vl-sort-i (mapcar '(lambda(x)(strcat (nth 1 x)(nth 2 x))) Summarylist) '<))
-
DOH!! .. why didn't I think of that ...
-
hi,
vl-sort does it directly or I misunderstood the problem
(vl-sort ls
'(lambda (e1 e2)
(and
(< (cadr e1) (cadr e2))
(< (caddr e1) (caddr e2))
)
)
)
(setq ls '(
("Block3" "GroundC" "XYZ" "BlahBlah" "xxxx")
("Block1" "GroundB" "RST" "BlahBlah" "xxxx")
("Block5" "GroundA" "ABC" "BlahBlah" "xxxx")
("Block2" "GroundA" "DEF" "BlahBlah" "xxxx")
)
)
return :
(
("Block5" "GroundA" "ABC" "BlahBlah" "xxxx")
("Block2" "GroundA" "DEF" "BlahBlah" "xxxx")
("Block1" "GroundB" "RST" "BlahBlah" "xxxx")
("Block3" "GroundC" "XYZ" "BlahBlah" "xxxx")
)
edit 1 : don't use it, I think it's false, I need to test it more
edit 2 : its false, so I only find a way to use vl-sort directly if, as you write, element's length is fixed:
(vl-sort ls
'(lambda (e1 e2)
(< (strcat (cadr e1) (caddr e1)) (strcat (cadr e2) (caddr e2)))
)
)
edit 3 : finally, I hope it's the good one :-)
(vl-sort ls
'(lambda (e1 e2)
(if (= (cadr e1) (cadr e2))
(< (caddr e1) (caddr e2))
(< (cadr e1) (cadr e2))
)
)
)
Bruno Toniutti
-
thanks a million guys, I can now move on to the next problem..... why is lisp so hard when you've been coding in VB for ages ????
-
Been out of town, so here is a late entry.
Like Bruno's the items can be other than strings.
(defun compare-items (L1 L2)
(cond
((equal (nth 1 L1) (nth 1 L2)) (< (nth 2 L1) (nth 2 L2)))
(t (< (nth 1 L1) (nth 1 L2)))
)
)
(mapcar '(lambda (x) (nth x lst)) (vl-sort-i lst 'compare-items))