英文:
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
结合使用来实现你的目标。compare
是 sort
通常使用的方法,它可以处理向量,但是它按错误的顺序排序,所以我们希望交换我们比较的元素的顺序:
(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]])
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论