2014-01-20 70 views
6

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

(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图形脚本的方式,我写的点总是会被订购,如分机是。我的问题是什么是一个命令,可以保证这样的排序偏好?

PS我试过(juxt last last)(juxt> <)pnts)但无济于事。

回答

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)) 
+0

我对_comp_和_juxt_都不太熟悉 - 请问这种排序方式会在最后一个降序,然后是第一个升序吗?你的例子显示它是这样的,但我想确定它会(我不明白这个例子在做什么)。 – user2958652

+0

不要介意noisesmith在另一个问题中回答。感谢这两者,并感谢noisesmith的诚实:)我将进一步研究_juxt_和_comp_。 – user2958652

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 

在这里,我们表明,洗牌会产生大量多种排序:

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

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

+0

啊不错。 Clojure Docs http://clojuredocs.org/clojure_core/clojure.core/sort建议在我需要访问第一个/最后一个项目时使用_sort-by_;那么我假设_sort-by_是关键字n'这样的宏。 – user2958652

+1

道文的回答实际上解决了这个问题,并且应该被认为是最好的答案。 – noisesmith

+0

真的吗?我是一名Clojure初学者,我认为道文的回答看起来有些ha。。他的方法会一样快吗? – user2958652

5

排序使用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))