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

在clojure的值列表中按第一个元素获取键

  •  0
  • smaug  · 技术社区  · 6 年前

    这与 Clojure get map key by value

    然而,有一点不同。如果HM是

    {1 ["bar" "choco"]}
    

    如果值列表是“bar”,那么得到1(键)作为第一个元素?如果有其他问题回答,请随时关闭/合并此问题。

    我试过这样的东西,但没用。

    (def hm {:foo ["bar", "choco"]})
    
    (keep #(when (= ((nth val 0) %) "bar")
             (key %))
          hm)
    
    3 回复  |  直到 6 年前
        1
  •  6
  •   Lee    6 年前

    可以过滤映射并返回结果序列中第一个项的第一个元素:

    (ffirst (filter (fn [[k [v & _]]] (= "bar" v)) hm))
    

    可以对向量值进行解构以访问第二个和/或第三个元素,例如

    (ffirst (filter (fn [[k [f s t & _]]] (= "choco" s)) 
                    {:foo ["bar", "choco"]}))
    

    过了你可能会发现的前几个元素 nth 更具可读性。

        2
  •  6
  •   Taylor Wood    6 年前

    另一种方法是使用 some :

    (some (fn [[k [v & _]]] (when (= "bar" v) k)) hm)
    

    你的例子非常接近实际,有一些细微的变化:

    (keep #(when (= (nth (val %) 0) "bar")
             (key %))
           hm)
    

    keep 一些 是相似的,但是 一些 只返回一个结果。

        3
  •  3
  •   leetwinski    6 年前

    除了以上所有(正确的)答案外,您还可以将地图重新索引为所需的格式,特别是如果搜索操作被频繁调用并且初始地图很大,这将允许您将搜索复杂度从线性降低到常量:

    (defn map-invert+ [kfn vfn data]
      (reduce (fn [acc entry] (assoc acc (kfn entry) (vfn entry)))
              {} data))
    
    user> (def data
            {1 ["bar" "choco"]
             2 ["some" "thing"]})
    #'user/data
    
    user> (def inverted (map-invert+ (comp first val) key data))
    #'user/inverted
    
    user> inverted
    ;;=> {"bar" 1, "some" 2}
    
    user> (inverted "bar")
    ;;=> 1