根据条件结果在地图中累积值的最佳方法

时间:2015-10-12 16:32:38

标签: dictionary clojure

我在Java中有一个算法来评估输入变量,如果它们不是null,它会进行一些处理并将它与地图相关联。 e.g:

myMap = new HashMap()

if ( a != null )
   myMap.put( "a", process( a ) )

if ( b != null )
   myMap.put( "b", process( b ) )

考虑到Clojure通常没有状态如何使用它以惯用的方式表达上述算法?

另外一个信息是,如果变量为null,则不应评估过程函数,因为它会产生空指针异常。所以像assoc-not-nil之类的东西不会这样做:(

感谢。

2 个答案:

答案 0 :(得分:5)

当我想像这样有条件地建立一个结果时,我倾向于转向cond->(条件线程优先)宏。

user> (let [a 4 b nil]
        (cond-> {}
          a (assoc a (* a a 42))
          b (assoc b (* b b 47 b))))
{4 672}

这从空映射{}的初始状态开始,然后如果a为真,它将使用表达式的结果作为下一阶段的值,如果它不是真的将值不变地传递给下一阶段。

如果我从一个集合中构建结果,那么我会使用以下函数来减少它:

user> (let [data [1 2 3 nil 4 5 nil 6]]
        (reduce (fn [result-so-far new-thing]
                  (if new-thing
                    (assoc result-so-far
                           new-thing
                           (* new-thing 42))
                    result-so-far))
                {}
                data))
{1 42, 2 84, 3 126, 4 168, 5 210, 6 252}

或者采取更简单的方法来过滤掉那些不应该首先回答问题的数据,然后减少它而不用担心。

答案 1 :(得分:0)

如果没有关于a和b的更多信息,可以执行以下操作,

a,b,c和d的定义如下:

a ;=> 33
b ;=> 44
c ;=> (not set) CompilerException ... Unable to resolve symbol: c in this context ...
d ;=> nil

(->> ['a 'b 'c 'd]
 (filter (comp (complement nil?) resolve)) ; filter unbound symbols ?
 (map #(vector (name %1) (eval %1)))       ; 'a -> ["a" 33] transform
 (filter (comp (complement nil?) second))  ; filter nils
 (map identity))                           ; here identity as dummy-fn for your process-fn
;=> (["a" 33] ["b" 44])

这个解决方案只有在命名变量(a,b,c,d)飞行时才真正有意义,而已经在某种seq上运行。 还有一个更好的方法