I am trying to sort a list of lists by the size of units.
Here is the unsorted list -
(setq List_Blocks
(list
(list "10x10" "UNIT DOWN-CC" 56)
(list "7.5x10" "UNIT DOWN-CC" 20)
(list "5x5" "UNIT DOWN-CC" 34)
(list "10x15" "UNIT EXTERIOR" 32)
(list "5x10" "UNIT DOWN-CC" 31)
(list "10x20" "UNIT EXTERIOR" 24)
(list "10x30" "UNIT EXTERIOR" 13)
(list "10x25" "UNIT EXTERIOR" 2)
)
)
I would like the list sorted by the first number before the "X" and then by the second number after the "X".
Example of sorted list -
(list "5x5" "UNIT DOWN-CC" 34)
(list "5x10" "UNIT DOWN-CC" 31)
(list "7.5x10" "UNIT DOWN-CC" 20)
(list "10x10" "UNIT DOWN-CC" 56)
(list "10x15" "UNIT EXTERIOR" 32)
(list "10x20" "UNIT EXTERIOR" 24)
(list "10x25" "UNIT EXTERIOR" 2)
(list "10x30" "UNIT EXTERIOR" 13)
Thanks in advance!!!
Solved! Go to Solution.
Solved by Kent1Cooper. Go to Solution.
Oops. Disregard my first post. I wasn't thinking about the items being strings. Try this, converts string to real for proper sorting.
(defun _sort (lst) (vl-sort lst (function (lambda (a b) (< (atof (car a)) (atof (car b)))))))
@alanjt_ wrote:This should do it... (defun _sort (lst) (vl-sort lst (function (lambda (a b) (< (car a) (car b))))))
That puts all the 10's first, followed by the 5's, and the 7.5 last, because it orders by the first character, not the numerical value represented prior to the x. I had tried this:
(vl-sort lst '(lambda (x y) (< (atof (car x)) (atof (car y)))))
which reads only the characters prior to the x, and at least gets all the 5's first followed by the 7.5 and then the 10's, but it also needs further elaboration. It puts all those with the same starting numerical characters together, and with the groupings in ascending order of the starting numbers, but within each grouping, they're just in the order in which they occur in the original list [in the OP's, 10x25 comes last, rather than before 10x30].
I think I recall something not too different from this coming up before. A Search may find it, but I haven't tried searching.
@alanjt_ wrote:@KenT: see my 2nd post. I realized the problem after my first post.
Yes, we crossed in the mail. But as with my similar version, that still leaves them not in the right order within those that start with the same numbers [unless those occur in the right order within the starting list]. However, this seems to do that, in very limited testing:
(vl-load-com); [if needed]
(defun testsort (lst / afterx)
(defun afterx (str)
(atof (substr str (+ 2 (vl-string-search "x" str))))
); defun -- afterx
(vl-sort ; by starting numbers on the list pre-sorted:
(vl-sort ; by end numbers first
lst
'(lambda (a b) (< (afterx (car a)) (afterx (car b))))
); vl-sort [inner]
'(lambda (x y) (< (atof (car x)) (atof (car y))))
); vl-sort [outer]
); defun -- testsort
I wouldn't be surprised if there's a more efficient way to do it.
Another variation
(defun testsort2 (lst / _numit) (defun _numit (s) (read (strcat "(" (vl-string-subst " " "x" s) ")") ) ;_ read ) ;_ defun (vl-sort lst '(lambda (l m) (setq l (_numit (car l)) m (_numit (car m)) ) ;_ setq (cond ((< (car l) (car m)) T) ((= (car l) (car m)) (< (cadr l) (cadr m))) ) ;_ cond ) ;_ lambda ) ;_ vl-sort ) ;_ defun