是否有一种干净,惯用的方法来检查地图的所有值是否为空或0。
例如,如果我有以下地图
{"id" 10 "Department" "UI Design" "managerid" 4}
什么是迭代地图值的最简洁方法,并确保字符串不为空("")或nil,而int / long不是0或nil。
基本上我在尝试将一些输入提交给DB之前尝试验证。我知道我可以使用像Prismatic / schema这样的库,但是现在我想知道如果没有它可以实现它。
此地图仅包含字符串和整数/长整数,但它可能包含其他类型。
有没有通用的方法呢?
答案 0 :(得分:5)
Multimethods可以为特定问题提供优雅的解决方案:
; for now dispatch is based only on value type
(defmulti valid? (fn [[k v]] (class v)))
(defmethod valid? java.lang.Long [[_ value]] (not (zero? value)))
(defmethod valid? java.lang.String [[_ value]] (not (empty? value)))
(defmethod valid? nil [_] false)
(defmethod valid? :default [_] true) ; valid for rest cases
查看整个地图:
(every? valid? your-map)
示例:
(every? valid? {:a 1 :b 0}) ; false
(every? valid? {:a 1 :b 1}) ; true
(every? valid? {:a 1 :b ""}) ; false
(every? valid? {:a 1 :b "a"}) ; true
(every? valid? {:a 1 :b "a" :c []}) ; true
很少注意到:
(not (empty? value))
可以替换为(not-empty value)
或(seq value)
,但在这两种情况下都会返回字符串的完整值而不是布尔值(它仍将评估为true
疗程)。nil
的数字或字符串,因为nil
有自己的类型。在上面的示例中,所有nil
值都被视为无效。如果对于某些键nils是可接受的 - 应该更改调度函数(fn [[k v]] (class v))
以考虑密钥。这个解决方案比像
这样的简单函数有点长(defn valid? [[k v]]
(cond (string? v) (not (empty? v))
...
:else true))
但它更易于维护和扩展。
修改即可。正如评论中所提到的,惯用方法是使用(seq coll)
代替(not (empty? coll))
,因为empty?定义为(not (seq coll))
。您可能仍希望保持(not (empty? coll))
检查,以使验证代码更明确,更明显。