I want to delete room by number. As you can see, the rooms is atom list and contains atoms. I got an exception: IllegalArgumentException Don't know how to create ISeq from: core.main$delete_room_by_id$fn__7541 clojure.lang.RT.seqFrom (RT.java:487)
I have this code:
(comment ------------- * DATA * ----------------- )
(def rooms "atomic list of atoms - rooms" (atom '()))
(comment ------------- * UTILS * ----------------- )
(defn enter-value [message]
(do (println message) (read-line)))
(comment ------------- * ADD ROOM * ----------------- )
(defn save-room "The function that will save provided room."
[number num-of-beds price]
(swap! rooms conj (atom {:number number
:num-of-beds num-of-beds
:price price
:is-ocupated false})))
(defn enter-room "This function will create room based on user input." []
(let [number (enter-value "Number...")
num-of-beds (enter-value "Number of beds...")
price (enter-value "Price...")]
(save-room number num-of-beds price)))
(comment ------------- * DELETE ROOM * ----------------- )
(defn delete-room-by-number "Delete room by number."
[number]
(swap! rooms remove #(not (= (:number #%) number))))
I think that swap! function don't put parameters for remove function as I want. I think that final command is: (remove rooms #(not (= (:number #%) number))). This is not good because I must to deref rooms like #rooms and pass it as second parameter of remove function.
Thanks for reading this.
There is a mistake in two functions. The value in save-room should not be a map in an atom, but just a map, because else you get atoms saved in an atom.
Also delete-by-room-number contained a mistake, the anonymous function wasn't written correctly.
(defn save-room "The function that will save provided room."
[number num-of-beds price]
(swap! rooms conj {:number number :num-of-beds num-of-beds :price price :is-ocupated false}))
(defn delete-room-by-number [num]
(swap! rooms #(remove (fn [room] (= (:number room) num)) %)))
Update:
It is more common practice to store an immutable, possibly nested, datatructure in an atom/ref,etc. A better option might be to not to go for a list but a vector or map, like this:
(def room-map {1 {:nums-of-beds 2 :price 30}, 2 {:nums-of-beds 4 :price 60}})
This way you use the room number as the key. This way you can never have a duplicate room number, because map keys must be unique.
You can update the map with assoc-in, update-in etc:
(def new-room-map (assoc-in room-map [2 :nums-of-beds] 40))
Value of new-room-map: {1 {:nums-of-beds 2, :price 30}, 2 {:nums-of-beds 40, :price 60}}
If you are going for the map representation of your rooms, use the function assoc-in in combination with swap! and an updated version of your room-map will be stored in the atom. If you have trouble understanding this, I suggest you read more on these functions:
http://clojuredocs.org/clojure_core/clojure.core/swap!
http://clojuredocs.org/clojure_core/clojure.core/assoc-in
Related
When use update-in we need to provide the full path to an element. But what if I want to update ALL elements whose second level key is :MaxInclude
e.g the input is
(def a {:store {:type "varchar"},
:amount {:nullable true, :length nil, :type "float", :MaxInclude "100.02"},
:unit {:type "int"},
:unit-uniform {:type "int" :MaxInclude "100"}
})
the required output is (convert MaxInclude from string to float/int based on theie type):
{:store {:type "varchar"},
:amount {:nullable true, :length nil, :type "float", :MaxInclude 100.02},
:unit {:type "int"},
:unit-uniform {:type "int" :MaxInclude 100}
}
I was thinking it would be nice to have a function like update-in that matches on key predicate functions instead of exact key values. This is what I came up with:
(defn update-all
"Like update-in except the second parameter is a vector of predicate
functions taking keys as arguments. Updates all values contained at a
matching path. Looks for keys in maps only."
[m [key-pred & key-preds] update-fn]
(if (map? m)
(let [matching-keys (filter key-pred (keys m))
f (fn [acc k]
(update-in acc [k] (if key-preds
#(update-all %
key-preds
update-fn)
update-fn)))]
(reduce f m matching-keys))
m))
With this in place, all you need to do is:
(update-all a [= #{:MaxInclude}] read-string)
The = is used as the first key matching function because it always returns true when passed one argument. The second is using the fact that a set is a function. This function uses non-optimised recursion but the call stack will only be as deep as the number of matching map levels.
(into {}
(map (fn [[k v]]
{k (if (contains? v :MaxInclude)
(update-in v [:MaxInclude] read-string)
v)})
a))
Here I am mapping over the key-value pairs and destructuring each into k and v. Then I use update-in on the value if it contains :MaxInclude. Finally, I pour the pairs from a list into a hash map.
Notes:
This will error on contains? if any of the main map's values are not indexed collections.
I use read-string as a convenient way to convert the string to a number in the same way the Clojure reader would do when compiling the string that is your number literal. There may be disadvantages to this approach.
As you can see my first element is somehow being skipped... at least println thinks it is.
(def example [(:1 :1 :1) (:2 :2 :2 :2) (:3 :3)])
(println example)
(defn countEachSequence [vec]
(println vec)
(let [varName (count vec)]
(println varName)
)
)
(map #(countEachSequence %) example)
Desired output is:
([1 3] [:2 4] [:3 2])
This is naming the group and count the amount of elements in that group.
This seems what you want:
(defn count-each-seq [v]
(map (fn [s] [(first s) (count s)]) v))
The above count-each-seq function returns a sequence of vector. You can print it later.
If you run the function in REPL, the result will displayed immediately.
There are three things to say in your code:
When you write code, you should separate the core logic and presentation (in this case, println). And your function should return a value.
Your parameter vec is actually a function name clojure.core/vec. Pick other name that doesn't conflict with the existing function name.
Using dash between word is the clojure (or LISP) convention. So name like count-each-sequence instead of camel case.
I have a vector of entities (maps), I have filtered this vector to those entities with a particular key. Then I apply a function to update some values in those entities, and now have a subset that I'd like to merge with the original superset.
world [{a} {b} {c} {d} {e}]
a [{b} {d} {e}] ; (filter matches? world)
b [{b'} {d'} {e'}] ; (map func a)
new-world [{a} {b'} {c} {d'} {e'}] ; (merge world b)
How can I merge my update b with the original world?
My map structure is:
{:id identity
:attrs {:property1 {:param1 value
:param2 value}
:property2 {}}
There can be a variable number of properties. Properties can have 0 ({}) or more params. The only part of the map that is changing are the values, and only some of them.
I have to peer into each map to identify it, and then merge accordingly? What is an idiomatic way to do this?
Clojure's map function can take multiple sequences, but won't compare my subset b to the whole superset world, only b number of world entities, and stop once b is exhausted.
> (map #(str %1 " " %2) [1 2 3 4 5] [6 7 8])
("1 6" "2 7" "3 8")
Have I chosen the wrong structure for my data in the first place? Would I be better off without a vector and just one map?
{:entid1
{:property1 {:param1 value :param2 value}
:property2 {}}
:entid2
{:property1 {:param1 value :param2 value}
:property2 {:param1 value}
:property3 {:param1 value :param2 value :param3 value}}}
This question looks similar but does not merge my vectors correctly.
Real world implementation
My actual code is part of a game I'm writing to familiarise myself with Clojure (ClojureScript in this instance).
The game state (world) is as follows:
[{:id :player,
:attrs
{:gravity {:weight 10},
:jump {:height 60, :falling false, :ground true},
:renderable {:width 37, :height 35},
:position {:x 60, :y 565},
:walk {:step 4, :facing :right},
:input {},
:solid {:blocked false}}}
{:id wall1,
:attrs
{:solid {},
:position {:x 0, :y 0},
:renderable {:width 20, :height 600}}}
{:id wall2,
:attrs
{:solid {},
:position {:x 780, :y 0},
:renderable {:width 20, :height 600}}}
{:id platform3,
:attrs
{:solid {},
:position {:x 20, :y 430},
:renderable {:width 600, :height 20}}}]
I update the world on each animation frame, then re-render the canvas.
(defn game-loop []
(ui/request-frame game-loop)
(-> world
system/update!
ui/render))
system/update! is:
(defn update! [world]
(let [new-world (->> #world
(phys/move #player/input-cmd))]
(player/clear-cmd)
(reset! world new-world)
#world))
My plan was to have a chain of systems updating the world in the thread last macro. I am in the process of writing phys/move.
This means that systems have to update the world, instead of just returning their effect on the world (vector of changes).
I'm contemplating if it's more manageable to have the system/update! function manage the effects on the world (applying the updates). So systems only return their list of changes. Something like:
(defn update! [world]
(let [updates []
game #world]
(conj updates (phys/move #player/input-cmd game))
(conj updates (camera/track :player game))
; etc.
(reset! world
(map #(update-world updates %) world))
#world))
Repeated (conj updates (func world)) feels clunky though. This is possibly more work than just merging updates (or returning an modified entity) in a system function.
How to elegantly pass state changes between my system functions (phys/move, camera/track), and subsystem functions (walk, jump)?
My stab at applying Joaquin's map only approach to my move system:
(ns game.phys)
(def step 4)
(def height 50)
(defn walk?
"is this a walk command?"
[cmd]
(#{:left :right} cmd))
(defn walks?
"update? equivalent"
[entity]
(contains? (:attrs entity) :position))
(defn walk
[cmd entity]
(if (walks? entity)
(let [x (get-in entity [:attrs :position :x]
op (if (= cmd :left) - +)
update {:attrs {:position {:x (op x step)}
:walk {:facing cmd}}}]
(merge entity update))
entity))
; cmd is a deref'ed atom that holds player input commands
; e.g. :left :right: :jump
(defn move
[cmd world]
(cond
(walk? cmd) (map #(walk input-cmd %) world)
(jump? cmd) (map #(jump height %) world)
:else world))
It is simpler than all that (having a vector of maps is something pretty common, and it may fit your problem properly). Instead of doing a filter and then a map, just do a map:
(defn update? [entity] ...)
(defn update-entity [entity] ...)
(defn update-world [world]
(let [update #(if (matches? %) (update-entity %) %)]
(map update world)))
This pattern of updating something or just leaving it as it is is pretty common, and it is idiomatic to make the functions that update something return the updated thing, or the old thing if it did nothing, so at the end it would be something like:
(defn update-entity?
"Predicate that returns if an entity needs updating"
[entity] ...)
(defn update-entity
"Updates an entity if it is needed.
Otherwise returns the unchanged entity"
[entity]
(if (update-entity? entity)
(assoc entity :something :changed)
entity))
(defn update-world [world]
(map update-entity world))
You can see some examples of this behavior in the game logic of this snake game:
https://github.com/joakin/cnake/blob/master/src/cnake/game.cljs#L54-L66
https://github.com/joakin/cnake/blob/master/src/cnake/game.cljs#L102-L114
I am trying to pass the (lazy) sequence returned from a map operation to another map operation, so that I can look up elements in the first sequence. The code is parsing some football fixtures from a text file (in row/column format), cleaning it up, and then returning a map.
Here is the code:
(ns fixtures.test.lazytest
(:require [clojure.string :as str])
(:use [clojure.test]))
(defn- column-map
"Produce map with column labels given raw data, return nil if not enough columns"
[cols]
(let [trimmed-cols (map str/trim cols)
column-names {0 :fixture-type, 1 :division, 2 :home-team, 4 :away-team}]
(if (> (count cols) (apply max (keys column-names)))
(zipmap (vals column-names) (map trimmed-cols (keys column-names)))
nil)))
(deftest test-mapping
(let [cols '["L" " Premier " " Chelsea " "v" "\tArsenal "]
fixture (column-map cols)]
(is (= "Arsenal" (fixture :away-team)))
(is (= "Chelsea" (fixture :home-team)))
(is (= "Premier" (fixture :division)))
(is (= "L" (fixture :fixture-type)))
)
)
(run-tests 'fixtures.test.lazytest)
The approach I'm taking is:
Clean up the vector of column data (remove leading/trailing spaces)
Using zipmap, combine column name keywords with their corresponding element in the column data (note that not all columns are used)
The problem is, using the trimmed-cols in zipmap causes
java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to clojure.lang.IFn
I think I know why this is happening ... as trimmed-cols is a LazySeq, the map called from zipmap is objecting to receiving a non-function as its first argument.
To fix this I can change the let to:
trimmed-cols (vec (map str/trim cols))
But this doesn't feel like the "best" option.
So:
Is there a good general solution for using the result of a map operation as the "function" argument to another map?
Is there a better approach for deriving a map of {: value} pairs from a vector of raw value data, where not all of the vector elements are used?
(I hesitate to ask for an idiomatic solution, but imagine somewhere there must be a generally accepted way of doing this.)
I am not entirely sure what you're after, but I can see why your code fails - like you said, trimmed-cols is not a function. Wouldn't this simply work?
I'm using :_dummy keys for columns that should be skipped. You can use as many as you like in the column-names vector: zipmap will merge them into one, which is removed by dissoc.
(defn- column-map
"Produce map with column labels given raw data, return nil if not enough columns"
[cols]
(let [trimmed-cols (map str/trim cols)
column-names [:fixture-type :division :home-team :_dummy :away-team]]
(if (>= (count cols) (count column-names))
(dissoc (zipmap column-names trimmed-cols) :_dummy)
nil)))
(column-map ["L" " Premier " " Chelsea " "v" "\tArsenal "])
; => {:away-team "Arsenal", :home-team "Chelsea", :division "Premier", :fixture-type "L"}
I am trying to write a Spider Solitaire player as an exercise in learning Clojure. I am trying to figure out how to deal the cards.
I have created (with the help of stackoverflow), a shuffled sequence of 104 cards from two standard decks. Each card is represented as a
(defstruct card :rank :suit :face-up)
The tableau for Spider will be represented as follows:
(defstruct tableau :stacks :complete)
where :stacks is a vector of card vectors, 4 of which contain 5 cards face down and 1 card face up, and 6 of which contain 4 cards face down and 1 card face up, for a total of 54 cards, and :complete is an (initially) empty vector of completed sets of ace-king (represented as, for example, king-hearts, for printing purposes). The remainder of the undealt deck should be saved in a ref
(def deck (ref seq))
During the game, a tableau may contain, for example:
(struct-map tableau
:stacks [[AH 2C KS ...]
[6D QH JS ...]
...
]
:complete [KC KS])
where "AH" is a card containing {:rank :ace :suit :hearts :face-up false}, etc.
How can I write a function to deal the stacks and then save the remainder in the ref?
Here is a solution that I came up with after studying the answer above. Note that I am still refining it and welcome suggestions for improvements, particularly the use of more idiomatic Clojure. Also note that these functions are defined in several separate files and do not necessarily appear in the order shown (if that makes a difference).
(def suits [:clubs :diamonds :hearts :spades])
(def suit-names
{:clubs "C" :diamonds "D"
:hearts "H" :spades "S"})
(def ranks
(reduce into (replicate 2
[:ace :two :three :four :five :six :seven :eight :nine :ten :jack :queen :king])))
(def rank-names
{:ace "A" :two "2"
:three "3" :four "4"
:five "5" :six "6"
:seven "7" :eight "8"
:nine "9" :ten "T"
:jack "J" :queen "Q"
:king "K"})
(defn card-name
[card show-face-down]
(let
[rank (rank-names (:rank card))
suit (suit-names (:suit card))
face-down (:face-down card)]
(if
face-down
(if
show-face-down
(.toLowerCase (str rank suit))
"XX")
(str rank suit))))
(defn suit-seq
"Return 4 suits:
if number-of-suits == 1: :clubs :clubs :clubs :clubs
if number-of-suits == 2: :clubs :diamonds :clubs :diamonds
if number-of-suits == 4: :clubs :diamonds :hearts :spades."
[number-of-suits]
(take 4 (cycle (take number-of-suits suits))))
(defstruct card :rank :suit :face-down)
(defn unshuffled-deck
"Create an unshuffled deck containing all cards from the number of suits specified."
[number-of-suits]
(for
[rank ranks suit (suit-seq number-of-suits)]
(struct card rank suit true)))
(defn shuffled-deck
"Create a shuffled deck containing all cards from the number of suits specified."
[number-of-suits]
(shuffle (unshuffled-deck number-of-suits)))
(defn deal-one-stack
"Deals a stack of n cards and returns a vector containing the new stack and the rest of the deck."
[n deck]
(loop
[stack []
current n
rest-deck deck]
(if (<= current 0)
(vector
(vec
(reverse
(conj
(rest stack)
(let
[{rank :rank suit :suit} (first stack)]
(struct card rank suit false)))))
rest-deck)
(recur (conj stack (first rest-deck)) (dec current) (rest rest-deck)))))
(def current-deck (ref (shuffled-deck 4)))
(defn deal-initial-tableau
"Deals the initial tableau and returns it. Sets the #deck to the remainder of the deck after dealing."
[]
(dosync
(loop
[stacks []
current 10
rest-deck #current-deck]
(if (<= current 0)
(let [t (struct tableau (reverse stacks) [])
r rest-deck]
(ref-set current-deck r)
t)
(let
[n (if (<= current 4) 6 5)
[s r] (deal-one-stack n rest-deck)]
(recur (vec (conj stacks s)) (dec current) r))))))
(defstruct tableau :stacks :complete)
(defn pretty-print-tableau
[tableau show-face-down]
(let
[{stacks :stacks complete :complete} tableau]
(apply str
(for
[row (range 0 6)]
(str
(apply str
(for
[stack stacks]
(let
[card (nth stack row nil)]
(str
(if
(nil? card)
" "
(card-name card show-face-down)) " "))))
\newline)))))
You could write a function to take chunks vectors of size items each from a given sequence and another one to drop those chunks from the front:
;; note the built-in assumption that s contains enough items;
;; if it doesn't, one chunk less then requested will be produced
(defn take-chunks [chunks size s]
(map vec (partition size (take (* chunks size) s))))
;; as above, no effort is made to handle short sequences in some special way;
;; for a short input sequence, an empty output sequence will be returned
(defn drop-chunks [chunks size s]
(drop (* chunks size) s))
Then maybe add a function to do both (modelled after split-at and split-with):
(defn split-chunks [chunks size s]
[(take-chunks chunks size s)
(drop-chunks chunks size s)])
Assuming that each card is initially {:face-up false}, you can use the following function to turn the last card on a stack:
(defn turn-last-card [stack]
(update-in stack [(dec (count stack)) :face-up] not))
Then a function to deal out the initial stacks / chunks from the the given deck:
(defn deal-initial-stacks [deck]
(dosync
(let [[short-stacks remaining] (split-chunks 6 5 deck)
[long-stacks remaining] (split-chunks 4 6 remaining)]
[remaining
(vec (map turn-last-card
(concat short-stacks long-stacks)))])))
The return value is a doubleton vector whose first element is the remainder of the deck and whose second element is a vector of the initial stacks.
Then use this in a transaction to take the Ref into account:
(dosync (let [[new-deck stacks] (deal-initial-stacks #deck-ref)]
(ref-set deck-ref new-deck)
stacks))
Better yet, keep the whole state of the game in a single Ref or Atom and switch from ref-set to alter / swap! (I'll use a Ref for this example, omit the dosync and switch alter to swap! to use an atom instead):
;; the empty vector is for the stacks
(def game-state-ref (ref [(get-initial-deck) []]))
;; deal-initial-stacks only takes a deck as an argument,
;; but the fn passed to alter will receive a vector of [deck stacks];
;; the (% 0) bit extracts the first item of the vector,
;; that is, the deck; you could instead change the arguments
;; vector of deal-initial-stacks to [[deck _]] and pass the
;; modified deal-initial-stacks to alter without wrapping in a #(...)
(dosync (alter game-state-ref #(deal-initial-stacks (% 0))))
Disclaimer: None of this has received the slightest amount of testing attention (though I think it should work fine, modulo any silly typos I might have missed). It's your exercise, though, so I think leaving the testing / polishing part to you is fine. :-)