在Clojure中对一个向量的向量进行排序

huangapple go评论58阅读模式
英文:

Sorting a vector of vectors in Clojure

问题

I want to sort this vector of vectors (of vectors) [[[5 5] [4 4] [8]] [[8 8] [2 2] [3]]] in descending order, so it becomes
[[[8 8] [2 2] [3]] [[5 5] [4 4] [8]]]

For clarity, [[[5 5] [4 4] [3]] [[5 5] [4 4] [8]]] would become
[[[5 5] [4 4] [8]] [[5 5] [4 4] [3]]]

The following doesn't work, not sure why:

(sort-by > [[[5 5] [4 4] [8]] [[8 8] [2 2] [3]]])

After many tries and research, I'm at the same point, can someone help?

英文:

I want to sort this vector of vectors (of vectors) [[[5 5] [4 4] [8]] [[8 8] [2 2] [3]]] in descending order, so it becomes
[[[8 8] [2 2] [3]] [[5 5] [4 4] [8]]]

For clarity, [[[5 5] [4 4] [3]] [[5 5] [4 4] [8]]] would become
[[[5 5] [4 4] [8]] [[5 5] [4 4] [3]]]

The following doesn't work, not sure why:

(sort-by > [[[5 5] [4 4] [8]] [[8 8] [2 2] [3]]])

After many tries and research I'm at the same point, can someone help?

答案1

得分: 4

你已经很接近了,而且你已经注意到了在Clojure中,sort 足够通用以处理向量。问题在于带有三个参数的 sort-by 不是你想要的,它试图使用 > 作为一个 key-fn,在排序之前将在每个元素上调用,而将 > 用单个参数调用会返回 true,因此不会进行排序。

但是,如果你查看 (doc sort),你会看到 sort 本身有一个三参数的版本,它可以实现你想要的功能:

clojure.core/sort
([coll] [comp coll])
  返回一个已排序的coll中的项目序列如果没有提供比较器则使用 compare比较器必须实现 java.util.Comparator 接口保证稳定性相等的元素不会重新排序如果coll是Java数组则它将被修改为了避免这种情况请对数组进行排序的副本

尝试使用 > 作为我们的比较方法是不起作用的,因为 > 处理数字,而不是向量:

(sort > [[[5 5] [4 4] [3]] [[5 5] [4 4] [8]]])
Execution error (ClassCastException) at java.util.TimSort/countRunAndMakeAscending (TimSort.java:355).
class clojure.lang.PersistentVector cannot be cast to class java.lang.Number (clojure.lang.PersistentVector is in unnamed module of loader 'app'; java.lang.Number is in module java.base of loader 'bootstrap')

但是我们可以使用在你的问题评论中提到的 compare 函数与 sort 结合使用来实现你的目标。comparesort 通常使用的方法,它可以处理向量,但是它按错误的顺序排序,所以我们希望交换我们比较的元素的顺序:

(sort #(compare %2 %1) [[[5 5] [4 4] [3]] [[5 5] [4 4] [8]]])
([[5 5] [4 4] [8]] [[5 5] [4 4] [3]])
英文:

You’re very close, and you have already noticed that sort in Clojure is general enough to handle vectors. The problem is that sort-by with three arguments is not what you want, that is trying to use > as a key-fn that will be called on each element before sorting, and calling > with a single argument trivially returns true, so no sort is performed.

But if you look at (doc sort) you can see that there is a three argument arity of sort itself that does what you want:

clojure.core/sort
([coll] [comp coll])
  Returns a sorted sequence of the items in coll. If no comparator is
  supplied, uses compare.  comparator must implement
  java.util.Comparator.  Guaranteed to be stable: equal elements will
  not be reordered.  If coll is a Java array, it will be modified.  To
  avoid this, sort a copy of the array.

Trying that using > as our comparison doesn’t work, though, because > deals with numbers, not vectors:

(sort > [[[5 5] [4 4] [3]] [[5 5] [4 4] [8]]])
Execution error (ClassCastException) at java.util.TimSort/countRunAndMakeAscending (TimSort.java:355).
class clojure.lang.PersistentVector cannot be cast to class java.lang.Number (clojure.lang.PersistentVector is in unnamed module of loader 'app'; java.lang.Number is in module java.base of loader 'bootstrap')

But we can use the compare function that was mentioned in a comment on your question with sort to achieve your goal. compare is what sort normally uses, and it can handle vectors, but it sorts in the wrong order, so we want to swap the order of the elements we are comparing:

(sort #(compare %2 %1) [[[5 5] [4 4] [3]] [[5 5] [4 4] [8]]])
([[5 5] [4 4] [8]] [[5 5] [4 4] [3]])

huangapple
  • 本文由 发表于 2023年6月8日 19:22:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76431333.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定