TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: hendie on March 22, 2007, 09:49:31 AM

Title: List Sorting
Post 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
Code: [Select]
(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

I need to return that list sorted as


Title: Re: List Sorting
Post by: JohnK on March 22, 2007, 10:10:45 AM
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:
Code: [Select]
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:
Code: [Select]
Command: (val-sort lst (lambda (x) (abs (car x))))
((1 . "B") (2 . "A") (3 . "C") (4 . "D") (5 . "E"))



Quote
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
>
>
>
>
Title: Re: List Sorting
Post by: Keith™ on March 22, 2007, 10:18:33 AM
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 ...

Code: [Select]
;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>
Title: Re: List Sorting
Post by: uncoolperson on March 22, 2007, 10:27:08 AM
Code: [Select]
(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

Quote
(("Block5" GROUNDA ABC BLAHBLAH XXXX) ("Block2" GROUNDA DEF BLAHBLAH XXXX) ("Block1" GROUNDB RST BLAHBLAH XXXX) ("Block3" GROUNDC XYZ BLAHBLAH XXXX))
Title: Re: List Sorting
Post by: VVA on March 22, 2007, 10:31:30 AM
Can be so
Code: [Select]
(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)  '<))
Title: Re: List Sorting
Post by: Keith™ on March 22, 2007, 10:50:04 AM
DOH!! .. why didn't I think of that ...
Title: Re: List Sorting
Post by: BrunoToniutti on March 22, 2007, 10:56:05 AM
hi,
vl-sort does it directly or I misunderstood the problem

Code: [Select]
(vl-sort ls
  '(lambda (e1 e2)
     (and
       (< (cadr e1) (cadr e2))
       (< (caddr e1) (caddr e2))
     )
   )
)

Code: [Select]
(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:
Code: [Select]
(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 :-)
Code: [Select]
(vl-sort ls
  '(lambda (e1 e2)
     (if (= (cadr e1) (cadr e2))
       (< (caddr e1) (caddr e2))
       (< (cadr e1) (cadr e2))
     )
   )
)

Bruno Toniutti
Title: Re: List Sorting
Post by: hendie on March 22, 2007, 11:09:47 AM
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 ????
Title: Re: List Sorting
Post by: CAB on March 26, 2007, 01:36:40 PM
Been out of town, so here is a late entry.
Like Bruno's the items can be other than strings.

Code: [Select]
(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))