如何在clojure中创建动态地图?

时间:2014-11-08 13:41:13

标签: clojure

我想创建一个像

这样的地图
{:a 1 
 :b 2 ;;in some condition
 :c 3 ;;in some other condition
}

但我不知道如何在地图结构中将[:b 2]之类的列表更改为:b 2

以下是我尝试的一些错误案例:

{:a 1
 (if (is condition1) [:b 2])
 (if (is condition2) [:c 3])
 ;...
}


{:a 1 
 (map indentity (if (is condition1) [:b 2]))
 (map indentity (if (is condition2) [:c 2]))
 ;;...
}

我试过的只会返回一个不是参数的序列。

有没有办法在没有宏的情况下处理?

4 个答案:

答案 0 :(得分:3)

(into {} [{:a 1}
          (if (is condition1) [:b 2])
          (if (is condition2) [:c 3])])

这样做是因为如果is condition1为false,则if表达式将返回nilconj会在地图上忽略该表达式。

答案 1 :(得分:1)

这是一种方法:

(fn [cond1 cond2]
  (into
   {:a 1}
   (map
    (fn [[c e]] (when c e))
    [[cond1 [:b 2]] [cond2 [:c 3]]])))

您可能希望传入与条目对相关的条件表。

答案 2 :(得分:0)

我认为merge是个不错的选择。

(merge {:a 1}
     (if condition1 {:b 2})
     (if condition2 {:c 3}))

答案 3 :(得分:0)

要回答原始问题,即将一对[:b 2]添加到地图中,您只需使用conj

user> (conj {:a 1} [:b 2])
{:b 2, :a 1}

现在,如果您只想在条件(谓词)为真时添加一对,您可以拥有一个函数,例如:

(defn conj-if-value-is-positive [m kv-pair]
  (if (< 0 (second kv-pair))
     (conj m kv-pair)
     m))

user> (conj-if-value-is-positive {:a 1} [:b 2])
{:b 2, :a 1}

接下来,让我们假设您有一个要添加到地图的对列表,具体取决于相同的条件,您可以reduce对序列:

user> (reduce conj-if-value-is-positive {:a 1} '([:b 2] [:c 3] [:d -1]))
{:c 3, :b 2, :a 1}

[:d -1]未添加到地图中,因为它不符合条件。 事实上,函数conj-if-value-positive不是很通用,可以分解为单独的步骤:

  1. 根据条件过滤对
  2. 将结果累积到地图中
  3. e.g。

    user> (reduce (fn [m p] (conj m p))
                  {:a 1}
                  (filter (fn [[k v]] (pos? v)) '([:b 2] [:c 3] [:d -1])))
    {:c 3, :b 2, :a 1}
    

    在您的示例中,您希望在不同的对上有不同的条件。这可以通过减少[[key value] predicate]的序列来实现。