Author Topic: Sorting points  (Read 1973 times)

0 Members and 1 Guest are viewing this topic.

Jeremy Dunn

  • Newt
  • Posts: 31
Sorting points
« on: January 15, 2018, 02:25:15 PM »
Let us say that I have a list of insertion points that are in a series of rows with one or more points with the same Y value. I want to create a list where the points are ordered going from left to right row by row from top to bottom. What is the best way to do this?

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Sorting points
« Reply #1 on: January 15, 2018, 02:33:39 PM »
1. Group points by y ordinate (will need to employ a fuzz value).
2. Sort groups by y ordinate (descending).
3. Sort within a group by x ordinate (ascending).
Engineering Technologist CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.com http://cadanalyst.slack.com http://linkedin.com/in/cadanalyst

ronjonp

  • Needs a day job
  • Posts: 7282
Re: Sorting points
« Reply #2 on: January 15, 2018, 03:07:36 PM »
Here's a simple example:
Code: [Select]
;; Sort master point list left to right
(setq pts (vl-sort pts '(lambda (a b) (< (car a) (car b)))))
;; While we have pts
(while (setq p (car pts))
  ;; Group by y values to get rows
  (setq tmp (vl-remove-if-not '(lambda (x) (equal (cadr p) (cadr x) 1e-8)) pts))
  ;; Append sublist to 'out'
  (setq out (cons tmp out))
  ;; Remove sublist items from master list
  (mapcar '(lambda (x) (setq pts (vl-remove x pts))) tmp)
)
;; Sort rows from top to bottom
(vl-sort out '(lambda (a b) (> (caar a) (caar b))))
« Last Edit: January 15, 2018, 03:13:17 PM by ronjonp »

Windows 10 x64 - AutoCAD /C3D 2020

Custom Build PC

Grrr1337

  • Swamp Rat
  • Posts: 761
Re: Sorting points
« Reply #3 on: January 15, 2018, 03:44:16 PM »
1. Group points by y ordinate (will need to employ a fuzz value).
2. Sort groups by y ordinate (descending).
3. Sort within a group by x ordinate (ascending).

A while back wrote something following these ^^ steps:

Code - Auto/Visual Lisp: [Select]
  1. ; Sort point list by X, then by Y, then by Z
  2. ; fA - determines the sorting order (i.e.: XYZ - first sort by X, then by Y, then by Z)
  3. ; and a Function Accessor, SYM, one of the following: ('XYZ 'XZY 'YXZ 'YZX 'ZXY 'ZYX)
  4. ; fz - fuzz
  5. ; dx, dy, dz - determine the sorting direction (like reversing part of the list), either ">" or "<" for each
  6. ; pL - Point list
  7. ; Usage Examples:
  8. ; (SortPointList 'XYZ 1e-3 > > > pL)
  9. ; (SortPointList 'XYZ 1e-3 < < < pL)
  10. ; (SortPointList 'YXZ 1e-3 > > > pL)
  11. (defun SortPointList ( fA fz dx dy dz pL / fp f )
  12.   (if
  13.     (and
  14.       (setq fp ; function part - of the complete sorting function
  15.         (cadr
  16.           (assoc fA ; function accessor - from the user, that provides the sorting order
  17.             (list ; assoc list of (<FooAccessor> <Foo>)
  18.               ; Unindented explanation (can be erased later) :
  19.               ; (list 'XYZ
  20.               ;   (lambda (a b c) ; a b c are X, Y, Z comparsions between 2 points using (equal) function
  21.               ;     (if a ; (equal x1 x2 fz) - if thats true, then compare the Y-es
  22.               ;       (if b ; (equal y1 y2 fz) - if thats true, then compare the Z-s
  23.               ;         (if c ; (equal z1 z2 fz) - if thats true, then the points are completely equal
  24.               ;           (> z1 z2) (> z1 z2) ; sort whatever
  25.               ;         ); if c
  26.               ;         (> y1 y2) ; else sort by Y-es
  27.               ;       ); if b
  28.               ;       (> x1 x2) ; else sort by X-es
  29.               ;     ); if a
  30.               ;   ); lambda
  31.               ; ); list
  32.               (list 'XYZ (lambda (a b c) (if a (if b (if c (dz z1 z2) (dz z1 z2) ) (dy y1 y2) ) (dx x1 x2) ) ) )
  33.               (list 'XZY (lambda (a b c) (if a (if c (if b (dy y1 y2) (dy y1 y2) ) (dz z1 z2) ) (dx x1 x2) ) ) )
  34.               (list 'YXZ (lambda (a b c) (if b (if a (if c (dz z1 z2) (dz z1 z2) ) (dx x1 x2) ) (dy y1 y2) ) ) )
  35.               (list 'YZX (lambda (a b c) (if b (if c (if a (dx x1 x2) (dx x1 x2) ) (dz z1 z2) ) (dy y1 y2) ) ) )
  36.               (list 'ZXY (lambda (a b c) (if c (if a (if b (dy y1 y2) (dy y1 y2) ) (dx x1 x2) ) (dz z1 z2) ) ) )
  37.               (list 'ZYX (lambda (a b c) (if c (if b (if a (dx x1 x2) (dx x1 x2) ) (dy y1 y2) ) (dz z1 z2) ) ) )
  38.             ); list
  39.           ); assoc
  40.         ); cadr  
  41.       ); setq fn
  42.       (setq f ; the complete sorting function
  43.         (lambda (p1 p2 / x1 y1 z1 x2 y2 z2 a b c) ; Sort By X, then by Y, then by Z:
  44.           (mapcar 'set '(x1 y1 z1) p1) (mapcar 'set '(x2 y2 z2) p2) ; dissect the point coordinates (for a clearer results)
  45.           (mapcar 'set '(a b c) (mapcar (function (lambda (a b) (equal a b fz))) p1 p2)) ; dissect the comparsion results
  46.           (fp a b c)
  47.         ); lambda
  48.       ); setq f
  49.     ); and
  50.     (vl-sort pL (function f)) ; sort the list
  51.   ); if
  52. ); defun SortPointList

So...
Code: [Select]
(setq pL '((1 1 2) (2 1 1) (2 2 2) (2 1 2) (2 3 2) (2 1 3) (1 1 3) (3 3 2) (1 1 3) (2 3 3) (3 1 1) (1 2 3) (1 2 1) (1 3 1) (1 3 0) (2 2 0) (2 3 4) (1 1 1) (2 3 0) (3 3 3) (3 4 2)))

_$ (SortPointList 'XYZ 1e-3 > < > pL)
((3 1 1) (3 3 3) (3 3 2) (3 4 2) (2 1 3) (2 1 2) (2 1 1) (2 2 2) (2 2 0) (2 3 4) (2 3 3) (2 3 2) (2 3 0) (1 1 3) (1 1 3) (1 1 2) (1 1 1) (1 2 3) (1 2 1) (1 3 1) (1 3 0))

_$ (SortPointList 'XYZ 1e-3 > > > pL)
((3 4 2) (3 3 3) (3 3 2) (3 1 1) (2 3 4) (2 3 3) (2 3 2) (2 3 0) (2 2 2) (2 2 0) (2 1 3) (2 1 2) (2 1 1) (1 3 1) (1 3 0) (1 2 3) (1 2 1) (1 1 3) (1 1 3) (1 1 2) (1 1 1))
_$ (SortPointList 'XZY 1e-3 > > > pL)
((3 3 3) (3 4 2) (3 3 2) (3 1 1) (2 3 4) (2 3 3) (2 1 3) (2 3 2) (2 2 2) (2 1 2) (2 1 1) (2 3 0) (2 2 0) (1 2 3) (1 1 3) (1 1 3) (1 1 2) (1 3 1) (1 2 1) (1 1 1) (1 3 0))
_$ (SortPointList 'YXZ 1e-3 > > > pL)
((3 4 2) (3 3 3) (3 3 2) (2 3 4) (2 3 3) (2 3 2) (2 3 0) (1 3 1) (1 3 0) (2 2 2) (2 2 0) (1 2 3) (1 2 1) (3 1 1) (2 1 3) (2 1 2) (2 1 1) (1 1 3) (1 1 3) (1 1 2) (1 1 1))
_$ (SortPointList 'YZX 1e-3 > > > pL)
((3 4 2) (2 3 4) (3 3 3) (2 3 3) (3 3 2) (2 3 2) (1 3 1) (2 3 0) (1 3 0) (1 2 3) (2 2 2) (1 2 1) (2 2 0) (2 1 3) (1 1 3) (1 1 3) (2 1 2) (1 1 2) (3 1 1) (2 1 1) (1 1 1))
_$ (SortPointList 'ZXY 1e-3 > > > pL)
((2 3 4) (3 3 3) (2 3 3) (2 1 3) (1 2 3) (1 1 3) (1 1 3) (3 4 2) (3 3 2) (2 3 2) (2 2 2) (2 1 2) (1 1 2) (3 1 1) (2 1 1) (1 3 1) (1 2 1) (1 1 1) (2 3 0) (2 2 0) (1 3 0))
_$ (SortPointList 'ZYX 1e-3 > > > pL)
((2 3 4) (3 3 3) (2 3 3) (1 2 3) (2 1 3) (1 1 3) (1 1 3) (3 4 2) (3 3 2) (2 3 2) (2 2 2) (2 1 2) (1 1 2) (1 3 1) (1 2 1) (3 1 1) (2 1 1) (1 1 1) (2 3 0) (1 3 0) (2 2 0))


_$ (SortPointList 'XYZ 1e-3 < < < pL)
((1 1 1) (1 1 2) (1 1 3) (1 1 3) (1 2 1) (1 2 3) (1 3 0) (1 3 1) (2 1 1) (2 1 2) (2 1 3) (2 2 0) (2 2 2) (2 3 0) (2 3 2) (2 3 3) (2 3 4) (3 1 1) (3 3 2) (3 3 3) (3 4 2))
_$ (SortPointList 'XZY 1e-3 < < < pL)
((1 3 0) (1 1 1) (1 2 1) (1 3 1) (1 1 2) (1 1 3) (1 1 3) (1 2 3) (2 2 0) (2 3 0) (2 1 1) (2 1 2) (2 2 2) (2 3 2) (2 1 3) (2 3 3) (2 3 4) (3 1 1) (3 3 2) (3 4 2) (3 3 3))
_$ (SortPointList 'YXZ 1e-3 < < < pL)
((1 1 1) (1 1 2) (1 1 3) (1 1 3) (2 1 1) (2 1 2) (2 1 3) (3 1 1) (1 2 1) (1 2 3) (2 2 0) (2 2 2) (1 3 0) (1 3 1) (2 3 0) (2 3 2) (2 3 3) (2 3 4) (3 3 2) (3 3 3) (3 4 2))
_$ (SortPointList 'YZX 1e-3 < < < pL)
((1 1 1) (2 1 1) (3 1 1) (1 1 2) (2 1 2) (1 1 3) (1 1 3) (2 1 3) (2 2 0) (1 2 1) (2 2 2) (1 2 3) (1 3 0) (2 3 0) (1 3 1) (2 3 2) (3 3 2) (2 3 3) (3 3 3) (2 3 4) (3 4 2))
_$ (SortPointList 'ZXY 1e-3 < < < pL)
((1 3 0) (2 2 0) (2 3 0) (1 1 1) (1 2 1) (1 3 1) (2 1 1) (3 1 1) (1 1 2) (2 1 2) (2 2 2) (2 3 2) (3 3 2) (3 4 2) (1 1 3) (1 1 3) (1 2 3) (2 1 3) (2 3 3) (3 3 3) (2 3 4))
_$ (SortPointList 'ZYX 1e-3 < < < pL)
((2 2 0) (1 3 0) (2 3 0) (1 1 1) (2 1 1) (3 1 1) (1 2 1) (1 3 1) (1 1 2) (2 1 2) (2 2 2) (2 3 2) (3 3 2) (3 4 2) (1 1 3) (1 1 3) (2 1 3) (1 2 3) (2 3 3) (3 3 3) (2 3 4))

Although the easier visualisation was thru a custom grread subfunction, where I could toggle the inputs:

(apply ''((a b c)(a b c))
  '(
    (( f L ) (apply 'strcat (f L)))
    (( L ) (if L (cons (chr (car L)) (f (cdr L)))))
    (72 101 108 108 111 32 87 111 114 108 100)
  )
)

Lee Mac

  • Seagull
  • Posts: 12489
  • London, England
Re: Sorting points
« Reply #4 on: January 15, 2018, 04:12:12 PM »

Jeremy Dunn

  • Newt
  • Posts: 31
Re: Sorting points
« Reply #5 on: January 15, 2018, 04:34:49 PM »
Thanks guys, I was coming up with a solution but I like yours better.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Sorting points
« Reply #6 on: January 15, 2018, 04:47:33 PM »
Quick & Dirty inspired by Ron's post:

Code: [Select]
(defun _GroupAndSort ( points fuzz / test sort result y )
    ;; Note: test exploits lexical globals y & fuzz
    (defun test (p) (equal y (cadr p) fuzz))
    (defun sort (l f g) (vl-sort l (function (lambda (a b) (f (g a) (g b))))))
    (while (setq y (cadar points))
        (setq
            result (cons (sort (vl-remove-if-not 'test points) < car) result)
            points (vl-remove-if 'test points)
        )
    )
    (sort result > cadar)
)

(setq points
   '(   
        (1191.46 378.027)
        (1247.31 347.734)
        (1247.31 378.027)
        (1125.24 392.376)
        (1274.43 363.279)
        (1191.46 332.986)
        (1166.73 347.734)
        (1191.46 347.734)
        (1125.24 363.279)
        (1191.46 392.376)
        (1247.31 363.279)
        (1125.24 347.734)
        (1247.31 392.376)
        (1191.46 363.279)
        (1166.73 378.027)
        (1166.73 332.986)
        (1274.43 378.027)
        (1274.43 347.734)
        (1125.24 332.986)
        (1247.31 332.986)
        (1274.43 392.376)
        (1166.73 392.376)
        (1274.43 332.986)
        (1125.24 378.027)
        (1166.73 363.279)
    )
)
   

Code: [Select]
(foreach group (_GroupAndSort points 0.5)
    (princ "\n")
    (foreach p group (princ p) (princ " "))
    (princ)
)

(1125.24 392.376) (1166.73 392.376) (1191.46 392.376) (1247.31 392.376) (1274.43 392.376)
(1125.24 378.027) (1166.73 378.027) (1191.46 378.027) (1247.31 378.027) (1274.43 378.027)
(1125.24 363.279) (1166.73 363.279) (1191.46 363.279) (1247.31 363.279) (1274.43 363.279)
(1125.24 347.734) (1166.73 347.734) (1191.46 347.734) (1247.31 347.734) (1274.43 347.734)
(1125.24 332.986) (1166.73 332.986) (1191.46 332.986) (1247.31 332.986) (1274.43 332.986)


Cheers.
Engineering Technologist CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.com http://cadanalyst.slack.com http://linkedin.com/in/cadanalyst

Lee Mac

  • Seagull
  • Posts: 12489
  • London, England
Re: Sorting points
« Reply #7 on: January 15, 2018, 06:00:02 PM »
Another, inspired by Michael's post:

Code: [Select]
(defun _groupandsort ( lst fuz / rtn tmp ycl yco )
    (while (setq yco (cadar lst))
        (setq lst (vl-remove-if '(lambda ( p ) (if (equal (cadr p) yco fuz) (setq tmp (cons p tmp)))) lst)
              rtn (cons (vl-sort tmp '(lambda ( a b ) (< (car a) (car b)))) rtn)
              ycl (cons yco ycl)
              tmp nil
        )
    )
    (mapcar '(lambda ( n ) (nth n rtn)) (vl-sort-i ycl '>))
)

Grrr1337

  • Swamp Rat
  • Posts: 761
Re: Sorting points
« Reply #8 on: January 15, 2018, 06:22:47 PM »
-={Challenge}=- Ultimate Sorter

I was wondering if it was possible to use a recursive algorithm to group a list of integer lists (like a list of points, but with more than 3 reals) in order to sort them.
Where the priority is from left to right, car->cadr->caddr->..->last [see the expected result and you'll understand] :
Code: [Select]
(foo
  '( ; a random messed up list of lists is given to be sorted:
    (1 3 6 2)
    (1 2 3 4)
    (1 3 4 5)
    (2 4 6 1 3)
    (3 2 4 5 4)
    (3 2 4 8 2)
    (2 5 5 1 2)
    (2 5 6 1 7)
    (1 2 3 5)
  )
)
>>
'( ; Priority, sort by the minimal (car) value, if there are other elements that are equal, then group and try sorting by (cadr), if some of them have equal, try (caddr)... and so on
  (1 2 3 4) ; CAR = 1
  (1 2 3 5) ; CAR = 1, the next ones are equal to the first, but the last one is above 4
 
  (1 3 4 5) ; CAR = 1, but CADR = 3, thats why is 3rd (because the (cadr) of the first set is with value of 2)
  (1 3 6 2) ; CAR = 1, and CADR = 3, but the 3rd element is higher than the previous item
 
  (2 4 6 1 3) ; CAR = 2 .. compare CADRs, if there are equals, then compare CADDRs
  (2 5 5 1 2)
  (2 5 6 1 7)
 
  (3 2 4 5 4) ; CAR-CADR have equals, compare CADDR
  (3 2 4 8 2)
)

I've called this idea 'Ultimate Sorter', but no idea if such thing is already figured out and its way over my head.
(apply ''((a b c)(a b c))
  '(
    (( f L ) (apply 'strcat (f L)))
    (( L ) (if L (cons (chr (car L)) (f (cdr L)))))
    (72 101 108 108 111 32 87 111 114 108 100)
  )
)

Lee Mac

  • Seagull
  • Posts: 12489
  • London, England
Re: Sorting points
« Reply #9 on: January 15, 2018, 06:38:46 PM »
-={Challenge}=- Ultimate Sorter

Code: [Select]
(defun foo ( l ) (vl-sort l 'bar))
(defun bar ( a b )
    (cond
        (   (not (and a b)) b)
        (   (= (car a) (car b)) (bar (cdr a) (cdr b)))
        (   (< (car a) (car b)))
    )
)

Grrr1337

  • Swamp Rat
  • Posts: 761
Re: Sorting points
« Reply #10 on: January 15, 2018, 06:49:42 PM »
Lee, just literally "what the hell?!"  :-o

No offence, but I expected that would be a tough job even for you.

Code: [Select]
(vl-string-subst "good" "tough" "tough job!")
EDIT:
Learned how important can be recursive functions that perform comparison just to return that boolean value for the vl-sort function.
« Last Edit: January 16, 2018, 07:22:46 AM by Grrr1337 »
(apply ''((a b c)(a b c))
  '(
    (( f L ) (apply 'strcat (f L)))
    (( L ) (if L (cons (chr (car L)) (f (cdr L)))))
    (72 101 108 108 111 32 87 111 114 108 100)
  )
)

kdub

  • Mesozoic keyThumper
  • SuperMod
  • Swamp Rat
  • Posts: 1386
  • class keyThumper<T>:ILazy<T>
Re: Sorting points
« Reply #11 on: January 15, 2018, 09:32:15 PM »
Quick & Dirty inspired by Ron's post:

Code: [Select]
< .. >
    ;; Note: test exploits lexical globals y & fuzz
< ... >

I had  bit of a laugh when I noticed this. Understanding Nuts and Bolts is more important than pretty printing.
called Kerry in my other life

Sometimes the question is more important than the answer.
#ridesober

ahsattarian

  • Newt
  • Posts: 59
Re: Sorting points
« Reply #12 on: February 18, 2021, 05:03:40 AM »
In a simple way    :




Code - Auto/Visual Lisp: [Select]
  1. (defun c:a ()
  2.   (defun myprint (txt)
  3.     (princ "\n  ")
  4.     (princ txt)
  5.     (princ "   ===>   ")
  6.     (eval (read (strcat "(princ \n" txt ")")))
  7.   )
  8.   (princ "\n  -------------------------------------------------------  ")
  9.   (setq li10 '(5 3 1 8 6 2 4 7))
  10.   (myprint "li10")
  11.   (setq li110 (vl-sort-i li10 '<))
  12.   (myprint "li110")
  13.   (setq li11 (mapcar '(lambda (a) (nth a li10)) li110))
  14.   (myprint "li11")
  15.   (setq li12 (vl-sort li10 '<))
  16.   (myprint "li12")
  17.   (setq li13 (vl-sort li10 (function (lambda (e1 e2) (< e1 e2)))))
  18.   (myprint "li13")
  19.   (setq li14 (vl-sort li10 '(lambda (e1 e2) (< e1 e2))))
  20.   (myprint "li14")
  21.   (princ "\n  -------------------------------------------------------  ")
  22.   (setq li20 '("1" "8" "5" "3" "6" "2" "4" "7"))
  23.   (myprint "li20")
  24.   (setq li21 (vl-sort li20 '<))
  25.   (myprint "li21")
  26.   (setq li22 (acad_strlsort li20))
  27.   (myprint "li22")
  28.   (princ "\n  -------------------------------------------------------  ")
  29.   (setq li30 '((7 2) (1 3) (8 4) (6 5)))
  30.   (myprint "li30")
  31.   (defun sub1 (lij funcj nthj) (vl-sort lij (function (lambda (e1 e2) (funcj (nthj e1) (nthj e2))))))
  32.   (setq li31 (sub1 li30 < car))
  33.   (myprint "li31")
  34.   (setq li32 (sub1 li30 > cadr))
  35.   (myprint "li32")
  36.   (princ "\n  -------------------------------------------------------  ")
  37.   (setq li40 '((1 3 6 2)
  38.                (1 2 3 4)
  39.                (1 3 4 5)
  40.                (2 4 6 1 3)
  41.                (3 2 4 5 4)
  42.                (3 2 4 8 2)
  43.                (2 5 5 1 2)
  44.                (2 5 5 1)
  45.                (2 5 6 1 7)
  46.                (1 2 3 5)
  47.               )
  48.   )
  49.   (myprint "li40")
  50.   (defun sub2 (a b)
  51.     (cond
  52.       ((not (and a b)) b)
  53.       ((= (car a) (car b)) (sub2 (cdr a) (cdr b)))
  54.       ((< (car a) (car b)))
  55.     )
  56.   )
  57.   (setq li41 (vl-sort li40 'sub2))
  58.   (myprint "li41")
  59.   (princ "\n  -------------------------------------------------------  ")
  60.   (textscr)
  61.   (princ)
  62. )





Jeremy Dunn

  • Newt
  • Posts: 31
Re: Sorting points
« Reply #13 on: February 19, 2021, 04:05:50 PM »
A slight variation. Suppose we have a list of pairs of enames of objects like blocks or text along with their insertion point as in

((ename1 ins1)(ename2 ins2) ... (enameN insN))

Suppose these items are in groups on several lines at different Y values. How can one get just the enames sorted left to right by X in separate lists by line going from top to bottom? In other words sort like

((enameX1 enameX2 ...) ;line1
 (enameX1 enameX2 ...) ;line2
 ...
 (enameX1 enameX2 ...)) ;lineN

Lee Mac

  • Seagull
  • Posts: 12489
  • London, England
Re: Sorting points
« Reply #14 on: February 19, 2021, 05:36:27 PM »
Revising my above posted function:
Code - Auto/Visual Lisp: [Select]
  1. (defun _groupandsort ( lst fuz / rtn tmp ycl yco xcl )
  2.     (while (setq yco (car (cdadar lst)))
  3.         (setq lst (vl-remove-if '(lambda ( p ) (if (equal (cadadr p) yco fuz) (setq xcl (cons (caadr p) xcl) tmp (cons (car p) tmp)))) lst)
  4.               rtn (cons (mapcar '(lambda ( n ) (nth n tmp)) (vl-sort-i xcl '<)) rtn)
  5.               ycl (cons yco ycl)
  6.               tmp nil
  7.               xcl nil
  8.         )
  9.     )
  10.     (mapcar '(lambda ( n ) (nth n rtn)) (vl-sort-i ycl '>))
  11. )

To test (with Points):
Code - Auto/Visual Lisp: [Select]
  1. (defun c:test ( / e i l s )
  2.     (if (setq s (ssget '((0 . "POINT"))))
  3.         (progn
  4.             (repeat (setq i (sslength s))
  5.                 (setq i (1- i)
  6.                       e (ssname s i)
  7.                       l (cons (list e (cdr (assoc 10 (entget e)))) l)
  8.                 )
  9.             )
  10.             (princ "\n(")
  11.             (foreach x l
  12.                 (princ "\n    ") (princ x)
  13.             )
  14.             (princ "\n)")
  15.             (princ "\n(")
  16.             (foreach g (_groupandsort l 1e-8)
  17.                 (princ "\n    (")
  18.                 (foreach x g (princ x) (princ " "))
  19.                 (princ "\010)")
  20.             )
  21.             (princ "\n)")
  22.         )
  23.     )
  24.     (princ)
  25. )

Results:

(
    (<Entity name: 7ffff706960> (26.5745 14.5973 0.0))
    (<Entity name: 7ffff706950> (24.1737 14.5973 0.0))
    (<Entity name: 7ffff706940> (22.126  14.5973 0.0))
    (<Entity name: 7ffff706930> (20.0077 14.5973 0.0))
    (<Entity name: 7ffff706920> (18.0307 14.5973 0.0))
    (<Entity name: 7ffff706910> (26.5745 16.1731 0.0))
    (<Entity name: 7ffff706900> (24.1737 16.1731 0.0))
    (<Entity name: 7ffff7068f0> (22.126  16.1731 0.0))
    (<Entity name: 7ffff7068e0> (20.0077 16.1731 0.0))
    (<Entity name: 7ffff7068d0> (18.0307 16.1731 0.0))
    (<Entity name: 7ffff7068c0> (26.5745 17.5373 0.0))
    (<Entity name: 7ffff7068b0> (24.1737 17.5373 0.0))
    (<Entity name: 7ffff7068a0> (22.126  17.5373 0.0))
    (<Entity name: 7ffff706890> (20.0077 17.5373 0.0))
    (<Entity name: 7ffff706880> (18.0307 17.5373 0.0))
)
(
    (<Entity name: 7ffff706880> <Entity name: 7ffff706890> <Entity name: 7ffff7068a0> <Entity name: 7ffff7068b0> <Entity name: 7ffff7068c0>)
    (<Entity name: 7ffff7068d0> <Entity name: 7ffff7068e0> <Entity name: 7ffff7068f0> <Entity name: 7ffff706900> <Entity name: 7ffff706910>)
    (<Entity name: 7ffff706920> <Entity name: 7ffff706930> <Entity name: 7ffff706940> <Entity name: 7ffff706950> <Entity name: 7ffff706960>)
)