在Clojure中对列表进行排序

6
我想要对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.
< p > (sort-by last) 似乎起到了作用,尽管这可能是因为点最初按第一个项目排序。我正在实现的ASCII/CLI图形脚本的方式将始终按pnts的顺序排序。我的问题是有什么命令可以保证这样的排序偏好?

PS:我尝试过使用(sort-by (juxt last first) (juxt > <) pnts),但没有成功。

3个回答

9

我认为您在使用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))

我对 compjuxt 不是很熟悉 - 这样会将节点按最后降序排列,然后按第一个升序排列吗?你的示例显示了这一点,但我想确保它会这样做(我看不出这个示例在做什么)。 - user2958652
不用介意,noisesmith已经在另一个问题中回答了。感谢两位,也感谢noisesmith的诚实:) 我将进一步研究_juxt_和_comp_。 - user2958652

7

Sort使用Java的sort进行排序,它是稳定的,因此您也可以只对其进行两次排序。

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

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

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

哦,不错。Clojure文档http://clojuredocs.org/clojure_core/clojure.core/sort建议在需要访问第一个/最后一个项目时使用_sort-by_;我认为_sort-by_是关键字等的宏。 - user2958652
1
DaoWen在下面的回答实际上更优雅地解决了这个问题,应该被接受为最佳答案。 - noisesmith
1
绝对至少和其他语言一样快,甚至可能更快。一旦你掌握了这门语言,简洁性实际上是一个额外的优势。它之所以有效,是因为(comp - last)给出了last的反向顺序,如果你对两个元素的列表进行排序,算法会通过首先按第一个元素排序,然后按第二个元素排序(如果第一个元素相等),从而自动完成我费力手动完成的工作。 - noisesmith
@A.Webb 你说得对,它们在性能上都非常接近,但 juxt 稍微领先一点 https://www.refheap.com/25861 - noisesmith
JVM中具有微生命周期的小对象的垃圾回收性能非常好。 - noisesmith
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接