Search code examples
clojureclojure-contrib

Does Clojure map include level specification?


In trying to write a mapping function that applies a function, i.e inc, dec, etc. to the elements of an input vector. The output is a vector with the function applied to each element and an indexing element.

Here is a sample of what I'm trying to input: Input 1: [+ [[1 2] [3 4 5]] 2]

Output1: [[2 2] [3 4]] [[5 4] [6 6] [7 8]]]

Input 2: [+ [1 2 3 4 5]]

Output 2: [[2] [4] [6] [8] [10]]

Symbolically: Input 2: [+ [a b c d e]]

Output 2: [[1+a] [2+b] [3+c] [4+d] [5+e]]

Input 3: [Plus, [[[[[1]]]]]]

Output 3: [[[[[[1+1]]]]] (would output 2 but I wrote out the operation)

Input 4: [Plus [[[[[1]]]]] 2]\

Output 4: [[1+[[[1]]]+[1 1]]]


Solution

  • There's clojure.core/map-indexed; it's similar but not exactly what you're looking for.

    E.g.

    (map-indexed vector '[a b c]) ;=> '([0 a] [1 b] [2 c])
    

    This is awfully close to what I think you're going for:

    (defn map-depth
      "Maps each element of s with an array of indices, as used by e.g. update-in,
       optionally at the given depth"
      ([f s depth path]
       (if (or (and depth (zero? depth))
               (not (sequential? s)))
         (f s path)
         (map-indexed (fn [i e]
                        (map-depth f e
                                   (when depth (dec depth))
                                   (conj path i)))
                      s)))
      ([f s depth]
       (map-depth f s depth []))
      ([f s]
       (map-depth f s nil [])))
    

    E.g.

    (map-depth vector '[a [b c] d])  ;=> '([a [0]] ([b [1 0]] [c [1 1]]) [d [2]])
    (map-depth vector '[a b c] 0)             ;=> '[[a b c] []]
    (map-depth vector '[[a b] [a b] [a b]] 1) ;=> '([[a b] [0]] [[a b] [1]] [[a b] [2]])
    

    Are you coming from a Mathematica background, though?

    It's important to remember also that Clojure's + operator doesn't play nicely with lists.

    In Mathematica you can do

    {1, 2, 3, 4} + 2 (* ->  {3 4 5 6} *)
    

    But Clojure will complain; you have to work around it.

    (+ [1 2 3 4] 2) ;=> ClassCastException
    (map (partial + 2) [1 2 3 4]) ;=> (3 4 5 6)