通过键 select 矢量地图的惯用方式

Idiomatic way to select a map in vector by a key

假设我有这个地图向量:

[{:title "Title1" :id 18347125}
 {:title "Title2" :id 18347123}
 {:title "Title3" :id 18341121}]

我想 select :id 18347125 的地图,我该怎么做?

我试过了

(for [map maps
      :when (= (:id map) id)]
    map)

感觉有点丑 return 是一个长度为 1 的序列,我只想 return 映射。

我不确定这是不是最简单的写法,但我认为这样更能表达你的意图:

(->> maps
     (filter #(= (:id %) id))
     first)

恕我直言,有几种方法可以解决您的问题,绝对惯用的方法是品味领域。这是我的解决方案,我只是将 "to select maps whose :id is 1834715" 翻译成 Clojure。

user> (def xs [{:title "Title1" :id 18347125}
               {:title "Title2" :id 18347123}
               {:title "Title3" :id 18341121}])
#'user/xs

user> (filter (comp #{18347125} :id) xs)
({:title "Title1", :id 18347125})

:id 关键字是一个在传递给它的集合中查找自身的函数。集合 #{18347125} 也是一个函数,用于测试传递给它的值是否等于 18347125。使用 Clojure 集作为谓词函数允许简洁的习惯用法。

如果您不仅需要查询一次,而且需要多次查询具有特定 ID 的地图,我建议您使数据类型与您的用例相匹配,即将向量更改为地图:

(def maps-by-id (zipmap (map :id maps) maps))

所以现在您的 ID 是这个新地图中的键:

user=> (maps-by-id 18347125)
{:title "Title1", :id 18347125}

这并不能完全满足您的要求,但可能仍然有用:

user=> (group-by :id [{:title "Title1" :id 18347125}
                      {:title "Title2" :id 18347123}
                      {:title "Title3" :id 18341121}])
{18347125 [{:title "Title1" :id 18347125}]
 18347123 [{:title "Title2" :id 18347123}]
 18341121 [{:title "Title3" :id 18341121}]}

现在您可以简单地通过 id 查找地图。详细了解 group-by on clojuredocs,这是一个非常有用的功能。

请注意,它将地图放在向量中。这是因为 group-by 被设计用来处理 grouping(即具有相同 key 的多个项目):

user=> (group-by :id [{:title "Title1" :id 123}
                      {:title "Title2" :id 123}
                      {:title "Title3" :id 18341121}])
{123 [{:title "Title1" :id 123} {:title "Title2" :id 123}]
 18341121 [{:title "Title3" :id 18341121}]}