代码之家  ›  专栏  ›  技术社区  ›  mehdix

如何在Clojure中重新实现“zipmap”?

  •  0
  • mehdix  · 技术社区  · 7 年前

    作为练习,我正在尝试重新实施 zipmap . 以下语句工作正常,它接受键和值并将其转换为映射:

    user=> (into {} (mapv vector [:a :b] [1 2]))
    {:a 1, :b 2}
    

    然而,当我试图将上述语句转换为函数时,我遇到了问题:

    user=> ((fn [& xs] (into {} (mapv vector xs))) [:a :b] [1 2])
    IllegalArgumentException Vector arg to map conj must be a pair 
    Clojure.lang.ATransientMap.conj (ATransientMap.java:37)
    

    我的实现有什么问题,为什么会这样?

    2 回复  |  直到 7 年前
        1
  •  4
  •   Taylor Wood    7 年前

    您可以使用 apply 要应用 xs mapv vector .

    ((fn [& xs] (into {} (apply mapv vector xs))) [:a :b] [1 2])
    

    这是由于变量参数与 xs型 . 没有 申请 ,你基本上会这样称呼它 (mapv vector [[:a :b] [1 2]]) 但你希望它被称为 (mapv vector [:a :b] [1 2]) .

        2
  •  3
  •   Gary    7 年前

    问题在于你如何将你的参数输入到你的匿名函数中

    [& xs] 将参数上卷到列表中

    所以在你的非函数版本中 (into {} (mapv vector [:a :b] [1 2])) 你正在映射向量 两个系列

    在你的函数版本中,你将向量映射到 一个系列

    (into {} (mapv vector [[:a :b] [1 2]])) 其计算结果为 (into {} [[[:a :b] [1 2]]]]) 这给了你一个错误

    可能的解决方案 :

    既然您试图重新实现zipmap,为什么不使用它使用的相同参数列表呢 [keys vals] 而不是 [&X] 然后这样编写函数:

    ((fn [keyz valz] (into {} (mapv vector keyz valz))) [:a :b] [1 2])

    您也可以自己展开该系列:

    ((fn [& xs] (into {} (mapv vector (first xs) (second xs)))) [:a :b] [1 2])

    我认为使用显式arg list是一种更精确的方法,因为您希望得到两个特定的集合