# Partial Alphabetical Sort ## Recommended Posts  I'm trying to find the latest revision from a list of revisions. The revisions start with A,B,C... Z, AA, AB, AC...ZZ, AAA, AAB, AAC... Then proceed to numbers 0, 1, 2, 3, etc. Any help would be appreciated!

```	(setq testCases (list "A" "AA" "AB" "BD" "AZ" "ZZ" "ZZZ" "11" "10" "9" "2" "1" "0" "Z" "X" "D" "C" "B"))

(setq testCases
(vl-sort testCases
'(lambda ( b a / x y )
(cond
(   (and (numberp x) (numberp y)) (< x y))
(   (numberp y))
(   (numberp x) nil)
(   (< a b))
)
)
)
)

(foreach test testCases
(progn
(princ "\n")
(princ test)
)
)

;Currently produces the following reverse-alphabetical sequence:
;11, 10, 9, 2, 1, 0, ZZZ, ZZ, Z, X, D, C, BD, B, AZ, AB, AA, A
;Desired sequence:
;11, 10, 9, 2, 1, 0, ZZZ, ZZ, BD, AZ, AB, AA, Z, X, D, C, B, A

```

##### Share on other sites  just cut & pasted this little frankenstein code together , totally expecting master Lee is gonna blow me out of the sky ```
(defun t1 ( / isnum tl li ln)
(defun isnum (n)(if (distof n) n nil))
(setq tl (list "A" "AA" "AB" "BD" "AZ" "ZZ" "ZZZ" "11" "10" "9" "2" "1" "0" "Z" "X" "D" "C" "B"))
(setq li (vl-remove-if-not 'isnum tl) ln (vl-remove-if 'isnum tl))
(append (vl-sort li '(lambda (a b)(> (atoi a) (atoi b))))
(mapcar '(lambda (x)(nth x ln))(vl-sort-i (mapcar '(lambda (y)(apply '+ (vl-string->list y))) ln) '(lambda (a b)(> a b))))
)
)

```

or in a little different form :

```(defun sort (l / s)
(append (vl-sort (vl-remove-if-not 'distof l) '(lambda (a b)(> (atoi a) (atoi b)))) (mapcar '(lambda (x)(nth x s))
(vl-sort-i (mapcar '(lambda (y)(apply '+ (vl-string->list y)))(setq s (vl-remove-if 'distof l))) '(lambda (a b)(> a b))))))

(sort '("A" "AA" "AB" "BD" "AZ" "ZZ" "ZZZ" "11" "10" "9" "2" "1" "0" "Z" "X" "D" "C" "B"))``` Edited by rlx
##### Share on other sites  The "A" -> "Z" then "AA" , "AB" -> "ZZ" and finally "AAA", "AAB"-> "ZZZ" gives a total of 18278 revisions! Are you ever going to get to the numbers!

If you just want to sort alphabetically then

`(setq testCases (vl-sort testCases '(lambda (x y) (< (apply '+ (vl-string->list x)) (apply '+ (vl-string->list y))))))`

##### Share on other sites  10 minutes ago, dlanorh said:

The "A" -> "Z" then "AA" , "AB" -> "ZZ" and finally "AAA", "AAB"-> "ZZZ" gives a total of 18278 revisions! Are you ever going to get to the numbers!

I think he works for the department that makes the corona rules , I hope the has enough space for all the changes

• 1
##### Share on other sites  12 minutes ago, rlx said:

I think he works for the department that makes the corona rules , I hope the has enough space for all the changes

It's a pity it's not corona brewery • 1
##### Share on other sites  It seems my complete solution ends up pretty similar to yours @rlx.

```(defun rh:ansort (lst / nlst alst)
(foreach x lst (cond ( (vl-every '(lambda (y) (< y 65)) (vl-string->list x)) (setq nlst (cons x nlst)))))
(setq alst (vl-sort (vl-remove-if '(lambda (x) (vl-position x nlst)) lst) '(lambda (x y) (< (apply '+ (vl-string->list x)) (apply '+ (vl-string->list y)))))
nlst (vl-sort nlst '(lambda (x y) (< (atoi x) (atoi y))))
lst (append alst nlst) ;; reverse alst and nlst if you want the numbers first
);end_setq
);end_defun
```

##### Share on other sites  @dlanorh in the end there are but so many roads leading to Rome

##### Share on other sites  1 hour ago, dlanorh said:

The "A" -> "Z" then "AA" , "AB" -> "ZZ" and finally "AAA", "AAB"-> "ZZZ" gives a total of 18278 revisions! Are you ever going to get to the numbers!

If you just want to sort alphabetically then

```
(setq testCases (vl-sort testCases '(lambda (x y) (< (apply '+ (vl-string->list x)) (apply '+ (vl-string->list y))))))```

This returns:

`("0" "1" "2" "9" "A" "B" "C" "D" "X" "Z" "10" "11" "AA" "AB" "BD" "AZ" "ZZ" "ZZZ") `

##### Share on other sites  did notice a little flaw in (apply '+ (vl-string->list method so here is a better one :

```; Gile
(defun a2i (s / i)
(if (= 0 (setq i (strlen s))) 0 (+ (* (- (ascii (strcase (substr s 1 1))) 64) (expt 26 (1- i)))(a2i (substr s 2)))))

(defun sort (l / s)(append (vl-sort (vl-remove-if-not 'distof l) '(lambda (a b)(> (atoi a)(atoi b))))(mapcar '(lambda (x)
(nth x s))(vl-sort-i (mapcar '(lambda (y)(a2i y))(setq s (vl-remove-if 'distof l))) '(lambda (a b)(> a b))))))```

output should now be correct

```
(sort '("A" "AA" "AB" "BD" "AZ" "ZZ" "ZZZ" "11" "10" "9" "2" "1" "0" "Z" "X" "D" "C" "B"))

("11" "10" "9" "2" "1" "0" "ZZZ" "ZZ" "BD" "AZ" "AB" "AA" "Z" "X" "D" "C" "B" "A")

``` Edited by rlx
• 1
##### Share on other sites  Oops, a badly worded reply. The (apply '+ (vl-string->list..)) method was for alphabetic lists only. The follow up code was for alpha and numeric string lists.

##### Share on other sites  Man, you all are fast!

No... realistically we'll probably never see more than maybe seven revisions... I just like to be feature complete Especially since my string increment function (which I use to get the next revision) is able to reach those values.

Follow-up challenge which is probably easier - can the code be simplified if we only need the latest revision? That way the list only needs to be inspected once per drawing?

Here's what I've got now, with some test cases:

```(defun ABC ( / )

(setq testCases (list "8" "7" "11" "10" "9"))
(princ "\nSet 1: ")(princ testCases)
(princ "\nDesired Result: 11")
(princ "\nActual Result:  ")(princ (_getLatestRev testCases))

(setq testCases (list "A" "B"))
(princ "\nSet 2: ")(princ testCases)
(princ "\nDesired Result: B")
(princ "\nActual Result:  ")(princ (_getLatestRev testCases))

(setq testCases (list "21" "0" "FC" "D" "C" "B"))
(princ "\nSet 3: ")(princ testCases)
(princ "\nDesired Result: 21")
(princ "\nActual Result:  ")(princ (_getLatestRev testCases))

(setq testCases (list "GAK" "GAJ" "GAP" "GAM"))
(princ "\nSet 4: ")(princ testCases)
(princ "\nDesired Result: GAP")
(princ "\nActual Result:  ")(princ (_getLatestRev testCases))

(setq testCases (list "A" "AA" "AB" "BD" "AZ" "ZZ" "ZZZ" "Z" "X" "D" "C" "B"))
(princ "\nSet 5: ")(princ testCases)
(princ "\nDesired Result: ZZZ")
(princ "\nActual Result:  ")(princ (_getLatestRev testCases))

(princ)
)

(defun _a2i (s / i)
(if (= 0 (setq i (strlen s))) 0 (+ (* (- (ascii (strcase (substr s 1 1))) 64) (expt 26 (1- i)))(_a2i (substr s 2)))))

(defun _sort (l / s)(append (vl-sort (vl-remove-if-not 'distof l) '(lambda (a b)(> (atoi a)(atoi b))))(mapcar '(lambda (x)
(nth x s))(vl-sort-i (mapcar '(lambda (y)(_a2i y))(setq s (vl-remove-if 'distof l))) '(lambda (a b)(> a b))))))

(defun _getLatestRev (s / )
(car (_sort s))
)```

##### Share on other sites  Seems to me (car (_sort s)) does the job. At my work our titleblock has its own separate attribute for the main (last) revision and one part of the titleblock has all the project revisions in it. So when I update the revison I read this main revision and then find the matching row in the project part. If all your titleblocks have the same structure this shouldn't be hard to do.

Edited by rlx
##### Share on other sites  And I think that's the method I'll use, unless there's a method that's simpler computationally. Unfortunately our title block cycles through 5 rows, and once the last row is reached we overwrite the first row. So the latest revision could appear in any of them ##### Share on other sites  So I went ahead and complicated my life by sorting dotted pairs instead of revisions. The keys are the rows in the revision block, and the values are the revision number strings. The values are what need sorting, not the keys. I set up a wrapper _sortPairsByValues and a lambda function that uses the sort function from @rlx. And it works! But what I failed to account for are the empty rows in the revision block which return nil values. Unfortunately the sort function sorts nil to the front of the list, not the back. I tried to remove the nils before running the sort, but it doesn't seem to be eliminating them.

```(defun _sortPairsByValues ( pairList / )
(setq pairList
(vl-remove-if
'(lambda (a / )
(= nil (cdr a))
)
pairList
)
)
(vl-sort pairList
;comparison function
'(lambda (a b / c)
(setq c (_sort (list (cdr a) (cdr b))))
(= (car c) (cdr a))
)
)
)```

##### Share on other sites  `(setq lst (vl-remove nil '(1 2 nil 3 4 nil nil)))`

##### Share on other sites  That doesn't work with dotted pairs though :(

For example:

'((0 . "0")(1 . "1")(2 . "2")(3 . nil))

##### Share on other sites  what is wrong with

```
(_sortPairsByValues '((0 . "0")(1 . "1")(2 . "2")(3 . nil)))
((2 . "2") (1 . "1") (0 . "0"))

```

looks to me its doing what its suppost to do?

##### Share on other sites  ```(ascii "0")
(ascii "a")
(ascii "A")

("3" "2" "AB" "1" "20" "AA" "AC")
(vl-sort '(3 2 6566 1 20 6565 6567 ) '<)
(1 2 3 20 6565 6566 6567)```

Had a think about this from the sorting point of view rather than title question just an idea if you make the items numbers only so 1 2 10 11 etc and A = 65 AA=6565 AZ=6590 it should work so long as less than 65 for numbers  not tested for lots of data.   ABC=656667  Note 0=48 9=57 so could convert numbers also. 20=5057

Just looking at the title  revs line by line and keeping is > value much easier.

Edited by BIGAL
##### Share on other sites  So the nil filter works fine, I'm just an idiot who left quotes around the nil turning them into strings in all my test cases. Thanks for the help!

That's a clever solution BIGAL, I may try to implement that as well.

Edit:

I tested the ascii conversion, and I think it would work, but it requires that all the values are padded to the maximum length. Otherwise all the single character letters and single digit numbers will sort below the two character letters.

Edited by plackowski
##### Share on other sites  Good to hear yes add 00. I did not do any real testing handy for a mixture of alpha and numbers. I did have a bubble sort at one stage not sure if it would work better.

Edited by BIGAL

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible. Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.

×   Pasted as rich text.   Restore formatting

Only 75 emoji are allowed.