0

I am stuck with a problem. So the problem is.

  • I have a map like this {:first {"value1" "value2" "value3"...} :second {"value1" "value2" "value3"...}....}.
  • I have a function which make a request to the server with parameters (first&value1) and return some information (it must make request with each keys and their values (first&value1, first&value2 ...second&value1...))
  • Next step is to generate new map like:

    {:first 
      {:value1 
        {subvalue1, subvalue2 ..} 
       :value2 
        {subvalue2-1,subvalue2-2}}    
     :second
      {:value3 
        {:subvalue3-1,:subvalue3-2}..}..}
    

Subvalues is the result of making a request with each key and each item of its value. And i want to repeat the operation once again(with 3 parameters when I make a request to the server) to achieve 4 times nested map: {first {second {third {fourth}}}}. Maybe somebody give me helpful advice how to do it.

3
  • If the value at :first is a series of values as your data suggests, then ["value1" "value2" "value3"] makes sense, but {"value1" "value2" "value3"} makes no sense at all because a map must have an even number of forms. Commented May 31, 2017 at 22:42
  • Could you please add an example of the actual data and their transformation you expect. The question is riddled with errors around the maps (odd number of elements) and you either want a list or a set there or it's just confusing. Also please add what you have tried yourself so far, to make it easier for us to pick up on that. Commented Jun 1, 2017 at 6:09
  • Sorry, i didnot correct explain the problem. The last nested map should have a vector or sequence as a value{:fourth ["value1" "value2"]....} Commented Jun 1, 2017 at 6:55

1 Answer 1

2

This function is a bit long-winded but does what you need it to do:

(defn rec-update
  [m f]
  (let [g (fn g [m args]
            (into {}
                  (for [[k v] m]
                    (if (instance? java.util.Map v)
                      [k (g v (conj args (name k)))]
                      [k (into {} (map #(let [args (into args [(name k) (name %)])]
                                          [(keyword %) (f args)])
                                       v))]))))]
    (g m [])))

The f parameter should be a function that takes a collection of params, and returns a vector of results. Here is a sample that picks random numbers of random responses:

(defn make-request
  [params]
  (vec (repeatedly (+ 1 (rand-int 3)) #(rand-nth ["r1" "r2" "r3"]))))

Though the below example does not demonstrate, the params given to this function will indeed be the nested values up to that point.

To use:

(def m {:first ["val1" "val2" "val3"], :second ["val4" "val5"]})

(rec-update m make-request)
=>
{:first {:val1 ["r2" "r2" "r3"], :val2 ["r2" "r2"], :val3 ["r1" "r3"]},
 :second {:val4 ["r3" "r3"], :val5 ["r2" "r1"]}}

Run it again on the result:

(rec-update *1 make-request)
=>
{:first {:val1 {:r2 ["r1" "r3" "r2"], :r3 ["r3" "r2"]},
         :val2 {:r2 ["r1" "r1"]},
         :val3 {:r1 ["r2"], :r3 ["r1" "r2" "r3"]}},
 :second {:val4 {:r3 ["r3" "r2"]}, :val5 {:r2 ["r1"], :r1 ["r2" "r3"]}}}

As you can see, any duplicate values returned from the request will only be represented once in the result map.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you very much, Josh, but I have one more question. I think I did not correctly explain the idea(sorry for this). My function f makes a request to the server and the request look likes (website/information/… it will be a full request I want and it should a one "branch" of my nested map). So at the first step, a make just a request with 1 param (first) and retrieve all information connected to it. Secondly i make a requst with 2 params (first and value1) and so on.
So now i have first level of my future map {:first ("value1" "value2") :second ("value1" "value2")....}
The above code works for this scenario @AndreiBelkevich -- the function f that you give to rec-update should expect one argument, which will be a vector containing stringified keywords from your map. You must write f, which is where you will make your request, and return a vector of responses. Write a test function that prints out its argument and pass it into rec-update and you will see what I mean.
Thank you very much for you suggestion. @Josh

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.