【问题标题】:How to transform Clojure map with collections as vals to seq of maps?如何将带有集合的 Clojure 映射转换为 val 到 seq 的映射?
【发布时间】:2018-01-19 13:10:58
【问题描述】:

我有一张地图,其中每个键都有一个集合作为值:

{:name ["Wut1" "Wut2"] :desc ["But1" "But2"]}

可以假设值集合具有相同数量的元素。

如何将其转换为一个列表(或向量),其中每个元素都是一个映射,其中键是原始集合中的键,值是 1 个值,例如:

[{:name "Wut1" :desc "But1"} {:name "Wut2" :desc "But2"}]

应该说之前不知道key的数量(所以我不能硬编码:name:desc

【问题讨论】:

    标签: clojure


    【解决方案1】:
    (fn [m]
      (let [ks (keys m)]
        (apply map (fn [& attrs]
                     (zipmap ks attrs))
               (vals m))))
    
    1. 获取用于标记所有内容的键列表
    2. 使用apply map(vals m) 中的列表列表从“对于每个属性,它应该具有的值列表”“转置”到“对于每个对象,它应该具有的属性列表” ”。
    3. zipmap 与第一部分中提取的密钥一起返回。

    【讨论】:

      【解决方案2】:

      作为一般规则apply map vector 将始终进行转置操作:

      (apply map vector '(["Wut1" "Wut2"] ["But1" "But2"]))
      ;;=> (["Wut1" "But1"] ["Wut2" "But2"])
      

      有了这个技巧,我们只需要确保zipmap每个向量对象(例如["Wut1" "But1"])都带有键:

      (fn [m]
        (->> m
             vals
             (apply map vector)
             (map #(zipmap (keys m) %))))
      ;;=> ({:name "Wut1", :desc "But1"} {:name "Wut2", :desc "But2"})
      

      另一个要遵循的规则是,当您有连续的maps 时会出现问题 - 实际上您应该将 map 函数 放在一起,而不是不必要地将项目从一个列表转移到另一个列表。 (这通常可以使用comp 来完成)。请参阅@amalloy 的解决方案,了解如何避免双重映射。当然,keys 函数调用也不应该像这里那样重复进行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-13
        • 2012-06-16
        • 2019-01-05
        • 1970-01-01
        • 2012-06-28
        • 1970-01-01
        相关资源
        最近更新 更多