英文:
How do I use sort-by on nested maps when the keys are strings, not keywords?
问题
This works with keywords
(sort-by (comp :rank second) >
{:1 {:bar "something" :rank 10} :2 {:bar "other" :rank 20}})
This fails when it's a string
(sort-by (comp "rank" second) >
{:1 {:bar "something" "rank" 10} :2 {:bar "other" "rank" 20}})
Error message is "Execution error (ClassCastException) at java.util.TimSort/countRunAndMakeAscending (TimSort.java:355).
java.lang.String incompatible with clojure.lang.IFn"
I take it the problem is that keywords can be a function but strings cannot be functions. What is the solution? I've tried playing around with get
without success.
英文:
This works with keywords
(sort-by (comp :rank second) >
{:1 {:bar "something" :rank 10} :2 {:bar "other" :rank 20}})
This fails when it's a string
(sort-by (comp "rank" second) >
{:1 {:bar "something" "rank" 10} :2 {:bar "other" "rank" 20}})
Error message is "Execution error (ClassCastException) at java.util.TimSort/countRunAndMakeAscending (TimSort.java:355).
java.lang.String incompatible with clojure.lang.IFn"
I take it the problem is that keywords can be a function but strings cannot be functions. What is the solution? I've tried playing around with get
without success.
答案1
得分: 2
comp
组合函数,所以您需要一个可以通过字符串获取键的函数:
user> (->> {:1 {:bar "something" "rank" 10} :2 {:bar "other" "rank" 20}}
(sort-by (comp #(get % "rank") second) >))
([:2 {:bar "other", "rank" 20}] [:1 {:bar "something", "rank" 10}])
英文:
comp
composes functions, so you'll need a function that can get the key by string:
user> (->> {:1 {:bar "something" "rank" 10} :2 {:bar "other" "rank" 20}}
(sort-by (comp #(get % "rank") second) >))
([:2 {:bar "other", "rank" 20}] [:1 {:bar "something", "rank" 10}])
答案2
得分: 1
(comp :rank second)
表达的意思与 (fn [x] (:rank (second x)))
写法相同。
类似地,(comp :rank "second")
会变成 (fn [x] (:rank ("second" x)))
,但是 "second"
是一个字符串,不能像函数一样调用。
可以使用一个函数替代,比如 #(get % "second")
或者只是 #(% "second")
。
英文:
The expression (comp :rank second)
is the same as writing (fn [x] (:rank (second x)))
.
Similarly, (comp :rank "second")
would be (fn [x] (:rank ("second" x)))
, but "second"
is a String. It cannot be invoked like a function.
Use a function instead, like #(get % "second")
or just #(% "second")
.
答案3
得分: 0
In Clojure, a keyword can act as a function, so it works with comp
. A String
does not have this special status. The easiest way is to make a dedicated function to extract the sort key. Here is one way with unit tests:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn nested-rank
[me]
(get (second me) "rank"))
(verify
; when iterating over a map, each map-entry looks like a 2-elem vector
(is= 10 (nested-rank [:1 {:bar "something" "rank" 10}]))
(let [data {:1 {:bar "something" "rank" 10}
:2 {:bar "other" "rank" 20}}]
(is= (sort-by nested-rank > data)
[[:2 {:bar "other" "rank" 20}]
[:1 {:bar "something" "rank" 10}]])))
Build using my favorite template project.
英文:
In Clojure, a keyword can act as a function, so it works with comp
. A String
does not have this special status. The easiest way is to make a dedicated function to extract the sort key. Here is one way with unit tests:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn nested-rank
[me]
(get (second me) "rank"))
(verify
; when iterating over a map, each map-entry looks like a 2-elem vector
(is= 10 (nested-rank [:1 {:bar "something" "rank" 10}]))
(let [data {:1 {:bar "something" "rank" 10}
:2 {:bar "other" "rank" 20}}]
(is= (sort-by nested-rank > data)
[[:2 {:bar "other" "rank" 20}]
[:1 {:bar "something" "rank" 10}]])))
build using my favorite template project.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论