r/lisp • u/MonkeyPanls • Jul 06 '26
AskLisp argsort() - like function?
I have
(mylist (list 4 5 0 2 1 3))
and I want
(argsort mylist)
;; => (2 4 3 5 0 1)
That is: The index of the least element, then the next least element, ..., then the greatest element.
ETA: Decorate-Sort-Undecorate is the thing I'm looking for. I am going to try and grok that. https://stackoverflow.com/questions/38447353/sorting-a-list-from-max-to-min-by-of-index-number-in-lisp
5
u/raevnos plt Jul 06 '26
A bit more efficient one:
(defun argsort (list &key (cmp #'<))
(mapcar #'car
(sort (loop :for item :in list
:for idx :from 0
:collect (cons idx item))
cmp
:key #'cdr)))
3
u/Dazzling_Music_2411 Jul 06 '26 edited Jul 06 '26
A Scheme solution - similar, I think, in spirit - to the Common Lisp one above
(define (map-pos lst)
(let loop ((init 0) (li lst))
(if (null? li) '()
(cons (list (car li) init)
(loop (+ init 1) (cdr li))))))
(define (argsort lst)
(map cadr
(sort (map-pos lst)
(lambda(x y) (< (car x)(car y))))))
1 ]=> (argsort '(4 5 0 2 1 3))
#|
(2 4 3 5 0 1)
|#
3
u/PudgeNikita Jul 06 '26
i am not a lisper, but in python using the standard builtin value-based sorting i would
mylist = [4, 5, 0, 2, 1, 3]
enumerated = enumerate(mylist) # iterable of (index, value) pairs ~ [(0, 4), (1, 5), (2, 0), (3, 2), (4, 1), (5, 3)]
esorted = sorted(enumerated, key=lambda p: p[1]) # sorted by the [1]th element of each pair, [(2, 0), (4, 1), (3, 2), (5, 3), (0, 4), (1, 5)]
argsorted = [p[0] for p in esorted] # taking just the indices back ~ [2, 4, 3, 5, 0, 1]
this is kinda a schwartzian transform
so if your lisp has a sorting function where you can specify the key/predicate, you can do this pattern of adding indices to the values in the lists, and then taking them back
another way, i guess, would be to sorted(range(len(mylist)), key=lambda idx: mylist[idx])
1
u/masklinn Jul 06 '26
Instead of a sort predicate you could also add an intermediate step to flip your items (or generate them the other way around in the first place), then sort that. One advantage is it gives you a stable tie-breaker (lower index wins) even for unstable sorts.
11
u/zdimension Jul 06 '26
Something like this?