Sorting Lists in Clojure

I am trying to sort a list of Clojure (or seq, if that's what he called) in a specific way. I would like it to be sorted in priority of the last item in descending order, then the first item in ascending order. Example:

(def pnts '((1 2) (2 4) (3 2) (4 10) (5 3) (6 1) (7 2))) (sort-by last > pnts) ;; ((4 10) (2 4) (5 3) (1 2) (3 2) (7 2) (6 1)) ;; Notice how (1 2), (3 2), (7 2) are sorted. This ;; is correct and is what I want. 

It seems that (sorting by last) does the trick, although this may be because the points are first sorted by the first element. The way I execute the ASCII / CLI graphics script that I write these points will always be ordered like pnts. My question is: what is a team that can guarantee such sorting?

PS I tried to do (sort-by (juxt last first) (juxt> <) pnts), but to no avail.

+6
source share
3 answers

I think you were on the right track using juxt . Assuming your points are all numbers, you can simply make last and - to emulate the downward natural order on the last component.

 user=> (sort-by (juxt (comp - last) first) (shuffle pnts)) ((4 10) (2 4) (5 3) (1 2) (3 2) (7 2) (6 1)) 
+8
source

Sorting uses Java sorting, which is stable, so you can also just sort twice

  (def pnts (shuffle '((1 2) (2 4) (3 2) (4 10) (5 3) (6 1) (7 2)))) (->> pnts (sort-by first <) (sort-by last >)) ;=> ((4 10) (2 4) (5 3) (1 2) (3 2) (7 2) (6 1)) 
+5
source

I mixed up the input to make sure the result is stable for arbitrary input order:

 (sort #(or (> (last %1) (last %2)) (and (= (last %1) (last %2)) (< (first %1) (first %2)))) (shuffle '((1 2) (2 4) (3 2) (4 10) (5 3) (6 1) (7 2)))) => ((4 10) (2 4) (5 3) (1 2) (3 2) (7 2) (6 1)) 

Here we check, even with 1000 reordering the input, there is only one output order:

 (count (into #{} (repeatedly 1000 (fn [] (sort #(or (> (last %1) (last %2)) (and (= (last %1) (last %2)) (< (first %1) (first %2)))) (shuffle '((1 2) (2 4) (3 2) (4 10) (5 3) (6 1) (7 2)))))))) => 1 

Here we show that a large number of orderings are made in random order:

 (count (into #{} (repeatedly 1000 (fn [] (shuffle '((1 2) (2 4) (3 2) (4 10) (5 3) (6 1) (7 2))))))) => 899 

(of course, since the random case of random sampling will vary, the result will usually be in the range of 850-950).

+3
source

All Articles