Adding element to a vector (conj function) and keep changes - clojure

The goal of my function is to read the input interpreting-vector and return a value after analysis.
To archieve my goal I need to add a string to a vector and keep the changes.
The conj function return a new vector but doesn't change my variable eq_code actually.
(conj eq_code (get-in vector [3 1])) doesn't change the value of the vector eq_code. I don't think repeat a let function with the variable eq_code would solve my problem.
Here is a piece of my code :
(defn interpreted-lang-while [interpreting-vector]
(let [vector interpreting-vector
;before_if code added to eq_code
eq_code [(str (get-in vector [1 1]) "0;")]]
(def interpret-eval-eq_code (->> (apply str eq_code) lang1-parser lang1-interpret))
(while
;eval the code (last value contains condition)
(not= 0 (do (conj eq_code (str (get-in vector [2 1]) ";"))(interpret-eval-eq_code) (prn (str "Eval condition : " (apply str eq_code)))))
;if the last value is not 0 =>add the statement_OK and eval the condition again
(do (conj eq_code (get-in vector [3 1])) (prn (str "End loop code : " (apply str eq_code)))))
(conj vector (str (interpret-eval-eq_code) ";"))
;last values contains 0 =>end of the while
(prn (str "Code equivalent : " eq_code))
(conj eq_code (get-in vector [4 1]))
(interpret-eval-eq_code)))
I execute the following line with clojure :
(interpreted-lang-while [:LangWHILE [:before_while "a=1; b= a+2; c="] [:condition_expression "a-3"] [:statements_OK "a=a+1;b=b+2;"] [:after_while " c+1;"]])
I get the following output on the terminal :
project.core=> "Eval condition : a=1; b= a+2; c=0;"
"End loop code : a=1; b= a+2; c=0;"
"Eval condition : a=1; b= a+2; c=0;"
"End loop code : a=1; b= a+2; c=0;"
"Eval condition : a=1; b= a+2; c=0;"
"End loop code : a=1; b= a+2; c=0;"
<Infinite loop ...>
Instead of
project.core=> "Eval condition : a=1; b= a+2; c=0;a-3;"
"End loop code : a=1; b= a+2; c=0;a-3;a=a+1;b=b+2;"
"Eval condition : a=1; b= a+2; c=0;a-3;a=a+1;b=b+2;a-3;"
<And so on ..>
Can you suggest me a way to add new element to my vector and changing my variable eq_code?
Thanks for your help.

Related

Removing the o coefficients along with their power and variable of a polynomial term in clojure

I created a polynomial function that returns the string based representation of the terms of polynomial added together, however i was having difficulties in removing terms from the string that contain the 0 coefficient and its giving me a different output
Below is my function:
(defn format-poly [poly]
(clojure.string/join ""
(map-indexed (fn [index item] (cond
(= index 0) item
(= (get item 0) \-) item
:default (str "+" item)))
(reverse (for [[pow coeff] (map-indexed vector (rseq (:coefficients poly))) ; remove whatever is causing a negative coeff to be ignored
]
(cond
(= coeff 0) (remove zero? [pow coeff])
(= coeff 1) (format "%s^%d",(:variable poly) pow)
(= pow 0) (format "%s",coeff)
:else
(format "%d%s^%d" coeff (:variable poly) pow)))))))
sample input:
(format-poly {:variable "x"
:coefficients [1 0 0 2 3 4]})
Expected output:
"x^6-2x^5+3x^4-4x^3+5x^2-6x^1+7"
i would propose gathering all the polynom print parts altogether into a flat collection, and then print all of them to string. Could look like this:
(defn format-poly [v coeffs]
(let [fmt-parts (mapcat (fn [coeff pow]
(when-not (zero? coeff)
[(if (neg? coeff) "-" "+")
(let [coeff (Math/abs coeff)]
(if (== 1 coeff) "" coeff))
(cond (zero? pow) ""
(== 1 pow) v
:else (str v "^" pow))]))
coeffs
(range (dec (count coeffs)) -1 -1))]
(apply str (if (= "+" (first fmt-parts))
(rest fmt-parts)
fmt-parts))))
user> (format-poly "x" [-1 -2 3 0 4 5])
;; "-x^5-2x^4+3x^3+4x+5"
user> (format-poly "x" [1 -2 3 0 4 5])
;; "x^5-2x^4+3x^3+4x+5"
user> (format-poly "x" [1 2 3 0 4 5])
;; "x^5+2x^4+3x^3+4x+5"

What is the meaning of double brackets within a Clojure function definition's parameters?

(defn foo [[a] b]
(println a b))
(foo "one" "two") ; => o two
(foo 1 2) ; => Execution error (UnsupportedOperationException) at user/foo (REPL:1).
; nth not supported on this type: Long
What are the second pair of brackets around a doing?
Or, a real-world example where I encountered it:
(parser/add-tag! :i18n
(fn [[k] context]
(->> k (keyword) (translate (or (:i18n/locale context) :en)))))
It is Clojure's syntax for destructuring.
(defn bar [[a b] c]
(println a b c))
would "pull out" the first and second items from the first argument passed to bar and immediately assign them to variables a and b respectively. It is functionally equivalent to:
(defn bar [vector c]
(let [a (nth vector 0) ; assign first item in first parameter to a
b (nth vector 1)] ; assign second item in first parameter to b
(println a b c))) ; c is passed & printed as-is
In your example:
(defn foo [[a] b]
(println a b))
Running (foo "one" "two") would mean "set a to first item in "one" and b to "two", then print a b.
In Clojure, strings are seq-able, so [[a]] in this specific case means "set a to the first character of the string "one", which is o.
(foo 1 2) fails because numbers (Longs) are not seq-able, so they cannot be destructured.
(fn [[k] context] … ) would mean "of the two arguments passed into this function, take the first item from the first argument and set it as k. Leave the second argument as-is."

Clojure: First Function and Tick Marks

(ns main.core)
(defn andexp [& resty]
(println "here is resty:" resty)
(first (resty))
)
I am very new to Clojure coming from a Java and C background
In the repl, the input has to be in this format:
(andexp '(John is a beginner so have mercy))
I need to include the tick mark ('). I want my program to print out "John."
There are two things happening here:
You are using & resty to destructure for a list of all the arguments; that is why you see the output of ((John ...)) (note the double (()).
Next you are calling resty, when you write (resty), which results in an error (remember, parens in clojure are always meaningful and not just for groupting things togehter etc. like in curly braces languages).
So this will do what you want:
repl=> (defn andexp [resty]
(println "here is resty:" resty)
(first resty))
#'repl/andexp
repl=> (andexp '(a b c))
here is resty: (a b c)
a
If you really want to destructure (like stated in the comments), you have to put your arguments into another pair of [] to destructure on the passed in list. E.g.
repl=> (defn andexp [[f & resty]]
(println "here is f and resty:" f resty)
(first resty))
#'repl/andexp
repl=> (andexp '(a b c))
here is f and resty: a (b c)
b
More infos about
destructuring
If you write it like so:
(defn andexp
[& resty]
(println "here is resty:" resty)
(first resty))
you will get a result:
(andexp '(John is a beginner so have mercy)) #=>
here is resty: ((John is a beginner so have mercy))
(John is a beginner so have mercy)
but you probably wanted something more like this:
(defn andexp
[& resty]
(println "here is resty:" resty)
(first resty))
(println :result (andexp 1 2 3 4) ) ; no wrapping parens
with result:
here is resty: (1 2 3 4)
:result 1
Another option:
(defn andexp
[& resty]
(println "here is resty:" resty)
(first (first resty))) ; or `ffirst`
(println :result (andexp [1 2 3 4]) )
with result:
here is resty: ([1 2 3 4])
:result 1
It may help to clarify the answer if you add more info about the use-case or goal.
For background, please see the documentation listed here:
https://github.com/io-tupelo/clj-template#documentation

Clojure: Manipulating certain items in list

I'm a Clojure newbie and having trouble with its immutable state. I'm trying to write a function that takes a list with the frames of a bowling game. For example, a list would look like ["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"]. I want the function to output a list that takes care of the frames that just have integers, and adds the numbers together. So, if the list above was inputted, the following list would be outputted: ["X" "3" "2/" "X" "9" "X" "4" "6" "X" "9"]. This was my attempt, but immutable state in Clojure is making it hard for me to understand how to go about this:
(defn eval-frames
[flist]
(loop [frames '()]
(if (not (= flist '()))
frames
(eval-normal (rest flist)))
(if (not (or (spare? flist) (strike? flist) (= flist ())))
(conj frames (+ (get (first flist) 0) ((get (first flist) 1))))
(conj frames (first flist)))
)
)
This just ends up outputting the first frame in the list, instead of the entire list. Any suggestions would be extremely appreciated!
There's a fair amount wrong with the code you posted:
The whole (if (not (= flist '())) part does nothing since you never use the results it gives back. You're thinking too imperative here. conj returns the "modified" list, it doesn't alter the original!
You never recur in the loop, so the loop only ever runs once.
I'd just use map for this. It iterates over a list, and "transforms" each element based on a function. I highly recommend getting as used to map and reduce as you can, because you'll be using them constantly.
My plan was this:
If all the characters in the frame are digits, sum the frame, else, leave the frame alone.
To sum the frame, I'm using parseLong to turn each character into a number, then(apply + to sum the parsed numbers, and then str to turn it back into a String.
(map
(fn [frame]
; Almost reads like English!
(if (every? #(Character/isDigit %) frame)
(->> frame ; Take the frame...
(map #(Long/parseLong (str %))) ; parse each character in the frame...
(apply +) ; then sum the parsed numbers...
(str)) ; and turn them back into a string.
frame)) ; Else, do nothing and leave the frame alone
["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"])
=> ("X" "3" "2/" "X" "9" "X" "4" "6" "X" "9")
This would have been simplified a bit if you had stored the scores as numbers originally instead of converting them to Strings. That would prevent the need for Long/parseLong, and the final call to str to turn each summed frame back into a String.
(map #(if (every? (fn [c] (<= (int \0) (int c) (int \9))) %)
(str (apply + (map read-string (map str %))))
%)
["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"])
or without the read-string:
(map #(if (every? (fn [c] (<= (int \0) (int c) (int \9))) %)
(str (apply + (map (fn [c] (- (int c) (int \0))) %)))
%)
["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"])
=> ("X" "3" "2/" "X" "9" "X" "4" "6" "X" "9")
(defn eval-frames [frames]
(map #(if (re-find #"\d\d" %)
(reduce + (map (fn [i](Integer. (str i))) (seq %))) %) frames))
So evaluating with a given frame would give :
(eval-frames ["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"])
=> ("X" "3" "2/" "X" "9" "X" "4" "6" "X" "9")

how to iterate over a list of maps in clojure and concatenate that to a string

I have a list of maps with two keys :path and :size
listOfMaps ({:path "a " :size "1 "}{{:path "b " :size " 2"}...)
how to iterate over it and concatenate its path and size to a string so that it is in between
that is
str "initial" "a" "1" "b" "2" .... "end"
ie path and size populated through loop should be between strings "initial" and "end"
(apply str
`("initial"
~#(mapcat (juxt :path :size) list-of-maps)
"end"))
Maybe it's heavy but I found it funny
(defn str-values [data]
(as-> data d
(map vec d)
(flatten d)
(remove keyword? d)
(concat ["initial"] d ["end"])
(apply str d)))
Outputs
"initiala1b2end"
Is that what you want ?
EDIT
Correction by OlegTheCat
(defn str-values [data]
(as-> data d
(map (juxt :path :size) d)
(flatten d)
(remove keyword? d)
(concat ["initial"] d ["end"])
(apply str d)))