0

我正在学习 Clojure,并想了解更多关于序列的信息。我有一个现实生活中的问题,我已将其简化为一般问题,但我不知道它是否有规范名称。希望下面的示例可以清楚地说明。

假设我有两个向量,src并且dst. 向量中的项目src本身就是向量,我需要将每个向量中的每个项目映射到dst.

(def src [ ["a1" "a2" "a3"] ["b1" "b2"] ["c1" "c2" "c3" "c4"] ])
(def dst [ "a" "b" "c" ])

我想制作以下地图:

{ :a1 "a", :a2 "a", :a3 "a", :b1 "b", :b2 "b", :c1 "c", :c2 "c", :c3 "c", :c4 "c" }

我可以在 Python 中很好地做到这一点,但 Clojure 的做法对我来说并不清楚。对于这个问题,我可以只构建一个地图,但我希望能够以一种通用的方式来完成,而不仅仅是针对这个实例。

在 Python 中,这将是:

src = [['a1', 'a2', 'a3'], ['b1', 'b2'], ['c1', 'c2', 'c3', 'c4']]
dst = ['a', 'b', 'c']
result = {}
for (s, d) in zip(src, dst):
    for x in s:
        result[x] = d

在 Clojure 中,我尝试从以下内容开始:

(interleave src dst)
;=> (["a1" "a2"] "a" ["b1" "b2" "b3"] "b" ["c1"] "c")

所以我已经展平了向量,但我不知道如何遍历映射键并选择值。

此外,zipmap它本身并不会让我走得太远:

(zipmap src (map keyword dst))
;=> {["c1"] :c, ["b1" "b2" "b3"] :b, ["a1" "a2"] :a}
;bogus result

现在我需要翻转映射键和值,并且仍然进行迭代。

我也没有成功构建for表达式:

(for [s src] (zipmap s dst)))
;=> ({"a2" "b", "a1" "a"} {"b3" "c", "b2" "b", "b1" "a"} {"c1" "a"})
;bogus result

我正在通过将两个向量配对来解决这个问题,但我似乎无法将向量中的src向量定位到适当的位置,以便我可以简单地zipmap将它们中的每一个与dst.

我怀疑答案真的很明显,但我的大脑仍然无法正常工作。也许在某个地方有一个into {}和/或assoc

任何指针?如果您有兴趣,我提到的现实问题是从 RNA 密码子映射到氨基酸。

4

3 回答 3

3

map可以采用多个 seq 进行迭代,例如:

(map + [1 2 3] [4 5 6])
;; => (5 7 9)

因此,这将是将要处理的值放入同一函数中的方法,从而导致对["a1" "a2" "a3"]/"a"等的处理...

(map
  (fn [src dst]
    ???)
  [["a1" "a2" "a3"] ["b1" "b2"] ["c1" "c2" "c3" "c4"]]
  ["a" "b" "c"])

zipmap接受一个键序列(我们有)和一个值序列(我们必须从单个值构造)。repeat可用于创建基于常量值的无限惰性序列:

(take 3 (repeat "a"))
;; => ("a" "a" "a")

和:

(zipmap ["a1" "a2" "a3"] (repeat "a"))
;; => {"a3" "a", "a2" "a", "a1" "a"}

这使得原始代码如下所示:

(map
  (fn [src dst]
    (zipmap src (repeat dst)))
  [["a1" "a2" "a3"] ["b1" "b2"] ["c1" "c2" "c3" "c4"]]
  ["a" "b" "c"])
;; => ({"a3" "a", "a2" "a", "a1" "a"} {"b2" "b", "b1" "b"} {"c4" "c", "c3" "c", "c2" "c", "c1" "c"})

最后,您可以使用 将所有这些映射合并为一个into,从而生成最后一段代码:

(into {} (map #(zipmap %1 (repeat %2)) src dst))
;; => {"a3" "a", "c2" "c", "c3" "c", "a1" "a", "b2" "b", "c4" "c", "a2" "a", "c1" "c", "b1" "b"}
于 2014-10-26T08:11:47.167 回答
2
user> (into {}
            (for [[sources, dest] (map list src dst),
                  source sources]
                 [(keyword source), dest]))
{:a2 "a", :b2 "b", :c3 "c", :a3 "a", :a1 "a", :b1 "b", :c4 "c", :c2 "c", :c1 "c"}

理解创建每个for源/目标对,然后into用于从这些对填充哈希映射。

于 2014-10-26T08:09:05.727 回答
1
(into {} (mapcat (fn [ss d] (map #(vector (keyword %) d) ss)) src dst))

;{:a3 "a", :c1 "c", :c2 "c", :b2 "b",
; :b1 "b", :c4 "c", :c3 "c", :a2 "a", :a1 "a"}

...但我更喜欢@noisesmith's -for这里更好。

于 2014-10-26T10:15:22.100 回答