这是我的输入数据:
[[:a 1 2] [:a 3 4] [:a 5 6] [:b \a \b] [:b \c \d] [:b \e \f]]
我想将此映射到以下内容:
{:a [[1 2] [3 4] [5 6]] :b [[\a \b] [\c \d] [\e \f]]}
这是我到目前为止所做的:
(defn- build-annotation-map [annotation & m]
(let [gff (first annotation)
remaining (rest annotation)
seqname (first gff)
current {seqname [(nth gff 3) (nth gff 4)]}]
(if (not (seq remaining))
m
(let [new-m (merge-maps current m)]
(apply build-annotation-map remaining new-m)))))
(defn- merge-maps [m & ms]
(apply merge-with conj
(when (first ms)
(reduce conj ;this is to avoid [1 2 [3 4 ... etc.
(map (fn [k] {k []}) (keys m))))
m ms))
以上产生:
{:a [[1 2] [[3 4] [5 6]]] :b [[\a \b] [[\c \d] [\e \f]]]}
我似乎很清楚问题出在merge-maps
,特别是传递给merge-with
(conj
)的函数,但是在我敲了一会儿之后,我'我准备有人帮助我。
我一般都是lisp的新手,特别是clojure,所以我也非常感谢那些没有专门解决这个问题的评论,还有我的风格,脑死亡等等。谢谢!
解决方案(足够接近):
(group-by first [[:a 1 2] [:a 3 4] [:a 5 6] [:b \a \b] [:b \c \d] [:b \e \f]])
=> {:a [[:a 1 2] [:a 3 4] [:a 5 6]], :b [[:b \a \b] [:b \c \d] [:b \e \f]]}
答案 0 :(得分:9)
(defn build-annotations [coll]
(reduce (fn [m [k & vs]]
(assoc m k (conj (m k []) (vec vs))))
{} coll))
关于您的代码,最重要的问题是命名。首先,我不会,尤其是在没有先了解您的代码的情况下,不知道annotation
,gff
和seqname
的含义。 current
也很模糊。在Clojure中,remaining
通常称为more
,具体取决于上下文,以及是否应使用更具体的名称。
在你的let语句gff (first annotation)
remaining (rest annotation)
中,我可能会利用解构,如下所示:
(let [[first & more] annotation] ...)
如果您更愿意使用(rest annotation)
,那么我建议您使用next
,因为如果它是空的,它将返回nil
,并允许您编写(if-not remaining ...)
而不是(if-not (seq remaining) ...)
比user> (next [])
nil
user> (rest [])
()
。
{{1}}
在Clojure中,与其他lisps不同,空列表是真实的。
This文章显示了惯用命名的标准。
答案 1 :(得分:4)
至少在给定的数据集上起作用。
(defn build-annotations [coll]
(reduce
(fn [result vec]
(let [key (first vec)
val (subvec vec 1)
old-val (get result key [])
conjoined-val (conj old-val val)]
(assoc
result
key
conjoined-val)))
{}
coll))
(build-annotations [[:a 1 2] [:a 3 4] [:a 5 6] [:b \a \b] [:b \c \d] [:b \e \f]])
我很抱歉没有对您的代码进行改进。我只是在学习Clojure,它更容易一块一块地解决问题,而不是理解更大的代码并找到问题。
答案 2 :(得分:4)
虽然我对你的代码没有任何评论,但我自己尝试了这个并提出了这个解决方案:
(defn build-annotations [coll]
(let [anmap (group-by first coll)]
(zipmap (keys anmap) (map #(vec (map (comp vec rest) %)) (vals anmap)))))
答案 3 :(得分:2)
这是我的分组利用分组,虽然这里的几个步骤真的关心的是返回向量而不是列表。如果你放弃了这个要求,它会变得更简单:
(defn f [s]
(let [g (group-by first s)
k (keys g)
v (vals g)
cleaned-v (for [group v]
(into [] (map (comp #(into [] %) rest) group)))]
(zipmap k cleaned-v)))
根据您的实际需要,您甚至可以通过分组来实现目标。
答案 4 :(得分:2)
(defn build-annotations [coll]
(apply merge-with concat
(map (fn [[k & vals]] {k [vals]})
coll))
所以,
(map (fn [[k & vals]] {k [vals]})
coll))
收集了[keys& amp;值]并返回{key [values]}
列表(apply merge-with concat ...list of maps...)
获取地图列表,将它们合并在一起,并在密钥已存在的情况下对值进行连接。