说我有这张表格的地图:
(def m {:a "A" :b "B"})
如果:a
和:b
都不是零,我想做点什么,我可以这样做:
(if-let [a (:a m)]
(if-let [b (:b m)]
... etc ))
或
(if (and (:a m) (:b m))
(let [{a :a b :b} m]
... etc ))
甚至
(if (every? m [:a :b])
(let [{a :a b :b} m]
... etc ))
是否有更简洁(即一线)的方法来实现这一目标?
答案 0 :(得分:7)
我认为这里可能需要一个宏来创建你想要的行为。我从来没有写过(但是)但是下面的表示向我暗示这可能相当简单:
(let [{:keys [a b]} m]
(when (every? identity [a b])
(println (str "Processing " a " and " b))))
使用:keys
形式的解构绑定和every?
使得键的向量的单个规范能够进行解构和检查,并且绑定的本地可用于以下代码块中。
这可以用来制作像(when-every? [keys coll] code-with-bindings)
我可以用宏代码更新这个答案,如果我可以花点时间弄清楚如何去做。
答案 1 :(得分:6)
你可以使用map destructuring - Clojure的一个有用功能。这也利用了and
短路的事实,并且第二张地图中未找到的第一张地图中的任何键都获得nil
,这是一个假值:
(let [{a :a b :b} {:a 1 :b "blah"}]
(and a b (op a b)))
好的,所以它是两条行而不是一行.......这也不区分nil
和其他假值。
答案 2 :(得分:1)
not-any?
是一个很好的捷径:
user> (not-any? nil? [(m :a) (m :b)])
true
user> (not-any? nil? [(m :a) (m :b) (m :d)])
false
user>
答案 3 :(得分:1)
如果密钥具有非零值,或者您是否需要返回非零键或值,我不太确定您要执行的操作。所以,我刚刚解决它,因为返回了非零键。
作为最终解决方案的一部分,您将使用以下内容作为中间步骤。
我正在展示我使用的所有步骤,不是迂腐,而是提供完整的答案。名称空间为repl-test
。它有一个主要与它相关。
repl-test.core=> (def m {:a "A" :b "B" :c nil})
#'repl-test.core/m
repl-test.core=> (keys m)
(:a :c :b)
然后最后:
; Check key's value to determine what is filtered through.
repl-test.core=> (filter #(if-not (nil? (%1 m)) (%1 m)) (keys m) )
(:a :b)
答案 4 :(得分:1)
顺便说一句,我发现了一个丑陋的单行,这是有效的,因为and
返回其参数列表中的最后一个东西,如果它们都是真的:
(if-let [[a b] (and (:a m) (:b m) [(:a m)(:b m)])]
(println "neither " a " nor " b " is falsey")
(println "at least one of " a " or " b " is falsey"))