如何将矢量映射到地图,重复键值?
这是我的输入数据:如何将矢量映射到地图,重复键值?
[[: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]]}
(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 [])
()
在Clojure中,与其他lisps不同,空列表是truthy。
This文章显示了惯用命名的标准。
至少在给定的数据集。
(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,它可以逐个解决问题而不是理解更大的代码并找出问题。
虽然我已经在你的代码没有评论,我想这对我自己和与此解决方案提出了:
(defn build-annotations [coll]
(let [anmap (group-by first coll)]
(zipmap (keys anmap) (map #(vec (map (comp vec rest) %)) (vals anmap)))))
这里是我的入门杠杆组通过,虽然在这里的几个步骤是真正关心与返回的载体,而不是名单。如果你删除一个要求,它变得简单一点:
(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)))
取决于你真正想要的东西,你甚至可以用只做组由度日。
'group-by'完全符合我的需要,实际上。谢谢! – 2010-09-12 17:31:20
(defn build-annotations [coll]
(apply merge-with concat
(map (fn [[k & vals]] {k [vals]})
coll))
所以,
(map (fn [[k & vals]] {k [vals]})
coll))
需要[键&值]的集合,并返回{键[值]}的列表
(apply merge-with concat ...list of maps...)
需要的地图列表,合并它们在一起,并且如果密钥已经存在则连接值。
谢谢,这实际上是我迄今为止首选的解决方案。我喜欢它的简洁,你的解释非常清楚。 – 2010-09-14 01:33:18
感谢您的评论,它有很大的帮助。 – 2010-09-12 17:30:04