在Clojure中排序列表

时间:2014-01-20 19:20:02

标签: sorting clojure

我正在尝试以特定的方式对Clojure列表(或seq,如果它是所谓的)进行排序。我希望它按降序排列最后一项的优先级,然后按升序排列第一项。一个例子:

(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.

(排序最后)似乎正在做这个技巧,尽管这可能是因为这些点最初是按第一个项排序的。我正在实现我正在编写点的ASCII / CLI图形脚本的方式总是按照 pnts 的顺序排序。我的问题是什么是可以保证这样的排序首选项的命令?

PS我试过(排序方式(最后一个)(juxt><)pnts),但无济于事。

3 个答案:

答案 0 :(得分:8)

我认为你使用juxt走在正确的轨道上。假设您的积分都是数字,您可以撰写last-来模拟最后一个组件的降序自然顺序。

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

答案 1 :(得分:5)

Sort使用Java的排序,这是稳定的,所以你也可以只排序两次

 (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))

答案 2 :(得分:3)

我已经改组输入以确保结果对于任意输入顺序是稳定的:

(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))

在这里我们验证,即使输入的1000次重新排序,输出只有一个排序:

(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

在这里,我们表明shuffle产生了大量的排序:

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

(当然,由于shuffle是随机的,结果会有所不同,但计数似乎通常在850 - 950范围内)