clojure - delete an element from a ref vector - vector

I'm using a vector of maps which defined as a referece.
i want to delete a single map from the vector and i know that in order to delete an element from a vector i should use subvec.
my problem is that i couldn't find a way to implement the subvec over a reference vector.
i tried to do it using:
(dosync (commute v assoc 0 (vec (concat (subvec #v 0 1) (subvec #v 2 5))))), so that the seq returned from the vec function will be located on index 0 of the vector but it didn't work.
does anyone have an idea how to implement this?
thanks

commute (just like alter) needs a function that will be applied to the value of the reference.
So you will want something like:
;; define your ref containing a vector
(def v (ref [1 2 3 4 5 6 7]))
;; define a function to delete from a vector at a specified position
(defn delete-element [vc pos]
(vec (concat
(subvec vc 0 pos)
(subvec vc (inc pos)))))
;; delete element at position 1 from the ref v
;; note that communte passes the old value of the reference
;; as the first parameter to delete-element
(dosync
(commute v delete-element 1))
#v
=> [1 3 4 5 6 7]
Note the that separating out the code to delete an element from the vector is a generally good idea for several reasons:
This function is potentially re-usable elsewhere
It makes your transaction code shorter and more self-desciptive

Related

Clojure reverse a list with do & recur forms

New to Clojure so I've been going through 4Clojure's questions to get familiar with the core library before jumping on a project and have ran into this question:
// Write a function which reverses a sequence.
(= (__ [1 2 3 4 5]) [5 4 3 2 1])
This is just one of the test-cases but here is what I had come up with:
(fn [x my-seq]
(if (empty? my-seq)
x
(do
(into x (take-last 1 my-seq))
(recur x (into [] (drop-last my-seq)))))) []
I was getting an empty vector [ ] after executing this code in a repl so
I modified the code like so:
(fn [x my-seq]
(if (empty? my-seq)
x
(recur (into x (take-last 1 my-seq)) (into [] (drop-last my-seq))))) []
Question is why was my previous code not working? To me it seems logically equivalent, the modified code just seems cleaner where it avoids the do form. Again I'm new to Clojure so i'm not entirely familiar with the do and recur forms.
(into x (take-last 1 my-seq)) is the problem.
Note that you cannot change x. (into x ...) creates a new vector and returns it.
However the return values of every statement inside (do ...) except for the last one are dropped. You are recurring with the original - empty - x.

How to make procedure iterate on every item in a list in Scheme?

I am writing a function in Scheme with Advanced Student settings. The function traverses through graph G and looks if there is a path between vertex X and Y. It "kinda" works, but not in all cases. I know where the problem lies, but I am not sure how to fix it. First I look if the vertex X I am looking on has been visited, if not I continue and mark it as visited. Then there is function find-adju. That function returns list of all of neighbours for given vertex. For example if I had a graph like this:
(define-struct graph (vertices edges))
(define-struct vertice (name visited))
(define-struct edge (start-vertice end-vertice length))
(define vertices-list
(list (make-vertice 0 0)
(make-vertice 1 0)
(make-vertice 2 0)
(make-vertice 3 0)
(make-vertice 4 0)
)
)
(define edges-list
(list (make-edge 0 1 0)
(make-edge 0 2 0)
(make-edge 1 3 0)
(make-edge 2 0 0)
(make-edge 2 4 0)
(make-edge 4 2 0)
)
)
(define G (make-graf vertices-list edge-list))
(traverse-graph? 0 4 G)
Then for given vertex 0 it would return list(1 2). Next I look at the list and ask, if my desired vertex Y is in it. If not, look again recursively at the first item in the list. But in doing so I lose information about all the other neighbours. In the same case, it would look at vertex 1, find all of his neighbours and then the procedure would quit, because it did not find a way. But the vertex 2 then remains unvisited. How can I make the procesure look at every item in the lsit and not just the first one?
(define (traverse-graph X Y G)
(cond
[(not(eq? (vertex-visited (find-vertex X (graph-vertices G))) VISITED))
(begin
(set-vertex-visited! (find-vertex X (graph-vertices G)) VISITED)
(cond
[(member Y (find-adju X (graph-edges G))) #t]
[(not (empty? (find-adju X (graph-edges G)))) (traverse-graph (car (find-adju X (graph-edges G))) Y G) ]
[else #f]
)
)
]
[else #f]
)
)
I thought of maybe returning the whole list with cdr instead of car to the traverse-function, but I don't know how to implement that. And how would I deal with the first step where X is a number and not a list.
EDIT:
I tried adding for-each which seems to be working ok, but the result is not giving me anything. No true or false. If I debug it step by step, I see that it is probably traversing correctly but when it reaches the [(member condition, it stops without returning anything, even when the condition is true.
(define (traverse-graph X Y G)
(cond
[(not(eq? (vertex-visited (find-vertex X (graph-vertices G))) VISITED))
(begin
(set-vertex-visited! (find-vertex X (graph-vertices G)) VISITED)
(cond
[(member Y (find-adju X (graph-edges G))) #t]
[(not (empty? (find-adju X (graph-edges G))))
(for-each (lambda (h)
(traverse-graph h Y G)
) (find-adju X (graph-edges G))
)
]
[else #f]
)
)
]
[else #f]
)
)
You were on the right path with for-each, but that function is an imperative construct. For each edge in your list it says "do this, do that", but does not keep any value. You would have more luck with map, which iterates over the list, and aggregates the results in a list.
With map, the result of your traverse-graph will be a tree with the shape of a depth-first-search traversal:
'(result0 (result1 (result3))
(result2 (result4)))
You could use (apply append (map (lambda …) (find-adju …)) to append the list of lists at each step, and prepend with cons the result for the current node. Don't forget to return a list containing a single element for the leaf nodes of your traversale, i.e use '(#t) and '(#f). This has however a big drawback the time complexity is O(N²) in the worst case. Imagine a graph where each node has two children: a leaf as its right child, and the rest of the graph as its left child:
(→ 0 2) (→ 0 1)
(→ 2 4) (→ 2 3)
(→ 4 6) (→ 4 5)
(→ 6 8) (→ 6 7)
(→ 8 10) (→ 8 9)
…
(→ 96 98) (→ 96 97)
(→ 98 100) (→ 98 99)
With that graph, your traversal will start drilling down the left edges until it reaches the leftmost node (100),
then return from that to node 98, go down to 99, and back up to 98, where it will append '(result100) to '(result99) and prepend result98,
then it will move back up to 96, examine 97, move back to 96, and append '(result98 result100 result99) to '(result97) and prependresult96`,
…
then it will move back up to 0, examine 1, move back to 0, and append '(… many results here …) to '(result1), and prepend result0.
Since append has to copy all the elements from the prefix, appending a list of length n to a list of length m will cost n operations (the second list is simply pointed to, and doesn't need to be copied, as the tail it forms is identical to the original whole second list), i.e it costs O(n) operations. The sequence of calls to append will be:
append 1 element to 1 element
append 3 elements to 1 element
append 5 elements to 1 element
append 7 elements to 1 element
append 9 elements to 1 element
…
append 99 elements to 1 element
So the total cost is 1+3+5+…+N, where N is the total number of nodes, which is roughly equivalent to N² times constant factor, hence the O(n²), which means that for a large number of nodes, it will be very slow. More about this at wikipedia.
To avoid the O(N²) cost, you can use an accumulator: each step will prepend a single item to the accumulator, and pass it around. This means that when handling a node, you have to give the current accumulator to its first neighbour, get back the modified accumulator for that whole sub-tree, pass that to the second neighbour, get back a new modified accumulator, pass that to the third neighbour, etc.
For that, you could write your own recursive function over the list, taking the latest accumulator and the list as an argument, and making a recursive call with the modified accumulator (obtained by processing the whole sub-tree), and the tail of the list.
You could also use the foldl function which abstracts over this pattern. The node-processing function will then follow this structure:
(define (process node accumulator)
(foldl ; the function applied to each neighbour of the list,
; it is passed the neighbour and the accumulator returned
; by the previous iteration
(lambda (neighbour latest-accumulator)
(if (visited? neighbour)
(process neighbour latest-accumulator)
latest-accumulator)) ; return unchanged
; initial accumulator for the first iteration,
; we already prepend the result for the current node,
; but that could be done afterwards, by prepending
; to the final result of `foldl`.
(cons (compute-result-for node) accumulator)
; the list of neighbours:
(neighbours-of node)))
Since this does never append lists, instead just prepending a single result at each step, it has a complexity of O(N) (without counting the cost of the neighbours-of function, see the note on hash tables and sets below). The flow of data is a bit convoluted though, sadly there's no better option with immutable data structures.
In your specific case, since you return a boolean, you could also simply use ormap, which will iterate over the list and return #t if the lambda returned #t for any element.
Does this have the O(N²) complexity like map? Think about why it does not.
As a side note, you should use #f and #t instead of 0 and VISITED, or #f and 'visited (the quoted ' symbol visited, which is considered true in an if statement, like all values other than #f).
For better performance, use hash tables and sets to store the edges, as looking for the edges in a list will cost a lot if there are many edges.
Finally, I would suggest putting the closing parenthesis of a block of code at the end of the last line, instead of having them alone on their line. This is the common practice in Scheme, Racket and most other Lisp variants, and makes the code more readable IMHO.
"but when it reaches the [(member condition, it stops without returning anything, even when the condition is true."
Check first if the list produced by
(find-adju X (graph-edges G)))
is empty. Then check if the list is non-empty and if Y is in that list. Then have an else case, where the list is non-empty but Y is not in the list of immediate neighbors.

Clojure map. Pass function multiple parameters

I'm looking for a way how to use map function in more custom way. If there is a different function for what I'm trying to achieve, could you please let me know this.
;lets say i have addOneToEach function working as bellow
(defn plusOne[singleInt]
(+ 1 singleInt))
(defn addOneToEach[intCollection] ;[1 2 3 4]
(map plusOne intCollection)) ;=>(2 3 4 5)
;But in a case I would want to customly define how much to add
(defn plusX[singleInt x]
(+ x singleInt))
(defn addXToEach[intCollection x] ;[1 2 3 4]
;how do I use plusX here inside map function?
(map (plusX ?x?) intCollection)) ;=>((+ 1 x) (+ 2 x) (+ 3 x) (+ 4 x))
I'm not looking for a function that adds x to each in the collection, but a way to pass extra arguments to the function that map is using.
another option to the already mentioned would be partial (note that in the example the order of the params does not matter, since you just add them, but partial binds them from left to right, so beware):
user=> (doc partial)
-------------------------
clojure.core/partial
([f] [f arg1] [f arg1 arg2] [f arg1 arg2 arg3] [f arg1 arg2 arg3 & more])
Takes a function f and fewer than the normal arguments to f, and
returns a fn that takes a variable number of additional args. When
called, the returned function calls f with args + additional args.
nil
user=> (defn plus-x [x i] (+ x i))
#'user/plus-x
user=> (map (partial plus-x 5) [1 2 3])
(6 7 8)
There are several ways to go about it. One is using an explicit local function via letfn:
(defn add-x-to-each [ints x]
(letfn [(plus-x [i]
(+ i x))]
(map plus-x ints)))
For this small piece of code this is probably overkill and you can simply streamline it via an anonymous function:
(defn add-x-to-each [ints x]
(map #(+ % x) ints))
Both of these solutions basically apply the use of a closure which is an important concept to know: it boils down to defining a function dynamically which refers to a variable in the environment at the time the function was defined. Here we defer the creation of plus-x (or the anonymous) function until x is bound, so plus-x can refer to whatever value is passed in to add-x-to-each.
You almost got it right.
There are several possible ways:
1.
(defn addXToEach[intCollection x]
(map #(plusX % x) intCollection))
#(%) means same as (fn [x] (x)) (be aware that x is being evaluated here).
2.
(defn addXToEach[intCollection x]
(map (fn [item] (plusX item x)) intCollection))
3.
(defn addXToEach[intCollection x]
(map #(+ % x) intCollection))
and then you don't have to define your plusX function.
Hope it helps!
You are applying map to one collection, so the function that map applies must take one argument. The question is, how is this function to be composed?
The function
(defn plusOne [singleInt]
(+ 1 singleInt))
... works. It is otherwise known as inc.
But the function
(defn plusX [singleInt x]
(+ x singleInt))
... doesn't work, because it takes two arguments. Given a number x, you want to return a function that adds x to its argument:
(defn plusX [x]
(fn [singleInt] (+ x singleInt))
You can use a function returned by plusX in the map.
It is when you compose such a function that you can use extra arguments. This kind of function, composed as an expression involving captured data, is called a closure.
For example, (plusX 3) is a function that adds 3 to its argument.
(map (plusX 3) stuff)
;(4 5 6 7)
As you see, you don't need to name your closure.
Specifically for + the following will also work:
(map + (repeat 4) [3 4 9 0 2 8 1]) ;=> (7 8 13 4 6 12 5)
Of course, instead '4' put your number, or wrap with (let [x 4] ...) as suggested above.
It might not be the most performant, although, I guess.

Count elements in a vector of vectors in clojure

If I have a matrix defined as:
(def m1 [[1 2 3][4 5 6][7 8 9]])
How do I go about counting the vectors within the vector in clojure. I know that (count m1) will return 3 which is the number of vectors I have in the initial vector but I can't remember how to count the inner vectors (its been a very very long time since I've had to deal with any lisp dialect). Also I do not want to flatten the vector and then count it because I need to count the values separately (ie. I want to return 3, 3, 3 because each of the inner vectors have 3 elements. One last restriction I guess is that I want to do this without using map right away because I realized I can simply do (map count m1).
That's actually very simple, just call:
(map count m1)
Or if you want to have your result also in vector:
(mapv count m1)
You'll want to use map. It will apply count to each element in the vector and return a list of counts.
(def m1 [[1 2 3][4 5 6][7 8 9]])
(map count m1)
=> (3 3 3)
Your edit: "I want to do this without using map."
(defn counts [vs]
(loop [vs vs, cs []]
(if (empty? vs)
cs
(recur (rest vs), (conj cs (count (first vs)))))))
One answer quite good but use count. Assume not using count and also not use map
((fn [lst]
(loop [l lst, n 0]
(if (empty? l)
n
(recur (rest l) (inc n)))))'(1 2 3))

Idiomatic way to sum multiple vectors in Clojure

Problem: I've got a collection of vectors or lists which I would like to find an idiomatic way to sum onto an existing vector possibly with uneven sized vectors.
Contrived example showing the setup:
=>(def collated-list [2 3 4 5 6 7 8])
=>(def lists-to-add (partition-all 3 collatedlist))
=>(def base-list [1 1 1])
I'd like the result to sum the broken down collated lists onto the base-list, for example, the first item would be 1 + 2 + 5 + 8 and so on.
What I've tried: I've tried a map and a for loop in couple of different ways but I seem to encounter either problems with Lazy Sequencing or problems of trying to add an Integer to a Vector.
These are my first experiments with Clojure so it's almost certainly me mis-understanding functional iteration here.
Thanks
First of all, it'll be much easier if lists-to-add contains lists of even length, so use partition instead of partition-all:
(def lists-to-add (partition 3 3 '(0 0) collated-list))
And then you can do the summing with map and recursion:
(defn sum-lists [base-lists lists-to-add]
(reduce #(map + %1 %2) base-list lists-to-add))
; List of list
(def lst (partition 5 (range 200)))
; Base list
(def base [1 1 1 1 1])
; Sum operation
(apply map (fn [& args] (apply + args) ) base lst)

Resources