1

I wonder what is the idiomatic way of doing complicated data structures changes. Here is a hashmap that contains lists, i want to take one of those list and move some items to the other one:

input:

{ :a (1 2 3) :b (4 5) }

output:

{ :a (2 3) :b (4 5 1) }

"first element of :a is added as last to :b"

In practice I need such structure to represent game state like:

{ :first_player { :deck (2 3 4 5) :hand (6 1) :discard () }
  :second_player { :deck (1 8 9 10) :hand (3) :discard (1 7) }
  :board { :first_player_side (1 3) :second_player_side (7 9) }}

As u can see i will need to move cards ids from different lists to different lists in various hashmaps (play from hand to board, move from board to discard pile etc). I just wonder how to make it in simple/readable way.

Thanks for answers.

2 Answers2

3

Clojure has an update-in function, designed for doing complicated data structures changes:

(defn magic [{:keys [a] :as m}]
  (-> m
      (update-in [:a] rest)
      (update-in [:b] concat (take 1 a))))

Or more general solution:

(defn move-els [m from to numel]
  (let [els (take numel (get m from))]
    (-> m
        (update-in [from] (partial drop numel))
        (update-in [to] concat els))))

Try it:

=> (move-els { :a '(1 2 3) :c "foo" :b '(4 5) } :a :b 2)
{:a (3), :c "foo", :b (4 5 1 2)}
Leonid Beschastny
  • 50,364
  • 10
  • 118
  • 122
0

Are you looking for map destructuring?

(defn frob [{:keys [a b]}]
    {:a (rest a) :b (conj b (first a))})

This doesn't do exactly what you want, of course, because that wouldn't be much fun.

See http://blog.jayfields.com/2010/07/clojure-destructuring.html for a good quick overview of restructuring.

pete23
  • 2,204
  • 23
  • 28
  • Using conj can lead to suprising results if people expect lists and vectors to behave the same. – noisesmith Apr 21 '14 at 19:34
  • Yes:-) Lovely, isn't it? http://stackoverflow.com/questions/7437833/inconsistency-with-clojures-sequences – pete23 Apr 21 '14 at 19:40