Flattening different types of result [duplicate] - functional-programming

This question already has answers here:
clojurescript thread macro nested vector problem
(3 answers)
Closed 6 months ago.
i want result like this,
["abc" "def" "ghi"] or ("abc" "def" "ghi")
problem with conj is :
cljs.user=> (conj ["IT","AB"] "MX" ["ad" "cd"])
["IT" "AB" "MX" ["ad" "cd"]]
problem with conj is :
cljs.user=> (conj ["IT","AB"] "MX" ["ad" "cd"])
["IT" "AB" "MX" ["ad" "cd"]]
however, i have found a solution for it, but not sure if using flatten is safe or not
((comp vec flatten conj) ["IT"] "MX")
["IT" "MX"]
does anyone know any predefined function just like conj or concat which i can use here

Try
user=> ((comp flatten conj vector) ["IT","AB"] "MX" ["ad" "cd"])
("IT" "AB" "MX" "ad" "cd")

Related

Racket: Apply string-replace to list

(apply string-replace ";" "" '("a" "b;" "c"))
gives me the error message
string-replace: arity mismatch;
the expected number of arguments does not match the given number
expected: 3 plus an optional argument with keyword #:all?
given: 5
arguments...:
As far as I understand, the problem is that the list is consed to the arguments of the string-replace function, whereas I would like to apply the function to every element of the list.
What would be the correct way to apply string-replace to a list?
(apply string-replace "b" "" '("b;"))
works, but returns "b;bb; whereas I would have expected "b".
To apply a function to all the elements of a list, use map (reference):
(map (lambda (str) (string-replace str ";" ""))
'("a" "b;" "c"))
produces
'("a" "b" "c")

Clojure: Apply a nested vector format to a flattened vector

For example, I have the following nested vector:
[[[0.582198689235419 -0.34713183143727 0.4685311493624731]
[-0.38928013774079284 -0.5901700383677557 -0.37573234072157]
[0.6716356761877877 -0.19645167952721243 -0.5700686091940252]]
[[0.0027162308840597005 -0.4483592764429284 -0.4766278022217257 -0.2724018313051576]
[-0.2765881229144672 -0.8030656496255356 -0.16159395457031567 -0.27432324260043084]
[-0.6154630466545907 -0.60573539482247 0.4417814561800192 -0.5559788990464504]
[0.6194560094536031 -0.3663074359460578 -0.5704311251195602 0.7194827876969362]]]
And I have the following flattened vector:
(0.5366343712173423
-0.816449781850872
-0.16066485785704843
0.9816561233924161
-0.09646744313584676
-0.2619662625757997
-0.9946004265996822
-0.14096299956754854
0.579260850612288
-0.827601452607939
-0.24934665032374648
-0.42272393175707873
0.11239245249400165
-0.29878238708035043
-0.61522274672097
0.8298721730401472
0.5016214138116059
0.11633537727916243
-0.0631891708267196
-0.26569217599364303
0.20900664784109668
0.2005869506108401
-0.2658279978034501
0.3383997403318165
-0.09353513546647907)
I want the flattened vector to be converted to a nested vector that follows the same structure as the nested vector presented above. Is there a core function in Clojure or a library that does this? I have some ideas of how to solve this problem, but all of them seem very very inefficient, and this operation will be used with big vectors.
Thank you very much in advance.
This was a fun question to answer, because it is one of the very few times when I think using a zipper makes things easier instead of harder. The idea is to just make a vector-zip of the nested vector, to represent the desired structure, and call zip/next on it repeatedly; whenever we get to a node which is a leaf, we replace its value with the next one from the input sequence.
Note that this assumes there are exactly as many items in the nested structure as in the flattened list; if that is not the case, you will probably get an error of some kind, who knows.
(require '[clojure.zip :as z])
(defn replace-values [structure values]
(loop [z (z/vector-zip structure)
values (seq values)]
(cond (not values) (z/root z)
(z/branch? z) (recur (z/next z) values)
:else (recur (-> z
(z/replace (first values))
(z/next))
(next values)))))
user> (replace-values '[[[0.582198689235419 -0.34713183143727 0.4685311493624731]
[-0.38928013774079284 -0.5901700383677557 -0.37573234072157]
[0.6716356761877877 -0.19645167952721243 -0.5700686091940252]]
[[0.0027162308840597005 -0.4483592764429284 -0.4766278022217257 -0.2724018313051576]
[-0.2765881229144672 -0.8030656496255356 -0.16159395457031567 -0.27432324260043084]
[-0.6154630466545907 -0.60573539482247 0.4417814561800192 -0.5559788990464504]
[0.6194560094536031 -0.3663074359460578 -0.5704311251195602 0.7194827876969362]]]
'(0.5366343712173423
-0.816449781850872
-0.16066485785704843
0.9816561233924161
-0.09646744313584676
-0.2619662625757997
-0.9946004265996822
-0.14096299956754854
0.579260850612288
-0.827601452607939
-0.24934665032374648
-0.42272393175707873
0.11239245249400165
-0.29878238708035043
-0.61522274672097
0.8298721730401472
0.5016214138116059
0.11633537727916243
-0.0631891708267196
-0.26569217599364303
0.20900664784109668
0.2005869506108401
-0.2658279978034501
0.3383997403318165
-0.09353513546647907))
[[[0.5366343712173423 -0.816449781850872 -0.16066485785704843]
[0.9816561233924161 -0.09646744313584676 -0.2619662625757997]
[-0.9946004265996822 -0.14096299956754854 0.579260850612288]]
[[-0.827601452607939 -0.24934665032374648 -0.42272393175707873 0.11239245249400165]
[-0.29878238708035043 -0.61522274672097 0.8298721730401472 0.5016214138116059]
[0.11633537727916243 -0.0631891708267196 -0.26569217599364303 0.20900664784109668]
[0.2005869506108401 -0.2658279978034501 0.3383997403318165 -0.09353513546647907]]]

Looking up values in a map with a vector of integer keys in Clojure

I have a map like this:
(def my-map {43423 43.3, 63452 32.02, 823828 67.43, ...})
and a vector of keys that are in a different order:
(def my-keys [63452 823828 43423 ...])
How can I call the my-keys vector on my-map to pull out the values and maintain the order of the vector, as below?
;=> [32.02 67.43 43.3 ...]
Any datatype returned is fine as long as the order is maintained.
Use map
(map my-map my-keys)
;=> (32.02 67.43 43.3)
This works because {} maps implement the function interface by looking up the argument in themselves.
({:foo 1 :bar 2} :bar)
;=> 2

Lisp, why is this number not a float

Using Common Lisp I am trying loop through a list of students and if the GPA is greater than or equal to 3.0 I want to push a 1 onto another list called equal_names. The problem I am having is the interpreter keeps saying the GPA in the comparison list is "not of type (or rational float)". Why am I getting this error?
Yes, this is for homework. Also this is my first time asking on here, so if you need anything else please let me know.
Sample of the list I am getting the GPA from, where the GPA is 2.307...:
(SETQ students (LIST
(LIST (LIST 'Abbott 'Ashley 'J) '8697387888 'NONE 2.3073320999676614)))
The code I have written:
(setq gpa_count ())
(loop for x in students
if(>= 3.0 (cdr (cdr (cdr x))))
do(push '1 gpa_count))
Given a non-empty list cdr returns the tail of that list, i.e. the list that contains all the elements of the list but the first. The important thing to note is that it returns a list, not an element. That is (cdr (cdr (cdr x))) returns the list (2.30733...), not the float 2.30733.
The loop iterates the outer list. To understand the code in the loop you can look at the first element in students, which is:
'((Abbott Ashley J) 8697387888 NONE 2.3073320999676614)
Now we are going to orientate the list. Every time you pass an element add a d.
Every time you pick a value or go to a list in the list you add an a.
To find how to access the number 2.307.... You look at the first element element in the list:
(Abbott Ashley J) d
8697387888 d
NONE d
Now we are at the part that you are interested in, ie. (2.3073320999676614)), thus you add an a. Now order those in reverse and put a c in front and a r in the end.. It becomes cadddr In light of that your loop should be:
(setq students '(("Mary Larson" 333 NONE 1.1)
("Mina Morson" 333 NONE 2.5)
("Magnus Outsider" 333 NONE 4.1)))
(setq gpa_count ())
(loop for x in students
if (>= 3.0 (cadddr x))
do (push '1 gpa_count))
gpa_count ; ==> (1 1)
Another example:
(setq x (1 (2 3) (3 4 (5 6) 7))) ; ==> (1 (2 3) (3 4 (5 6) 7))
To get the 3*. We follow the parts. 1 == d, (2 3) == a, 2 ==d, 3* == a. In reverse: adad and add c and r to the ends ==> cadadr. thus:
(cadadr '(1 (2 3) (3 4 (5 6) 7))) ; ==> 3
To get the 5. we do the same 1 == d, (2 3) == d and then we have the list we want ==a.
Then 3 ==d, 4 ==d, (5 6) ==a. The 5 is the first element == a. In reverse aaddadd. Now CL guarantees 4 letters accessors so we need to split it up in 4s from the right. Thus it becomes:
(caadr (cdaddr '(1 (2 3) (3 4 (5 6) 7)))) ; ==> 5
Now, without describing you can pick any number or list. Eg. to get (5 6) ddadda, in reverse and split up becomes (cadr (cdaddr x))
Hope it helps.
If your data format is consistent then
(fourth x)
will return the GPA.
Going further,
(setf (symbol-function 'gpa)(function fourth))
would provide
(gpa x)
as "an accessor" for the gpa in the data structure.
My CLISP 2.49 gives this error message:
*** - >=: (2.307332) is not a real number
Let's look at that error message: >=: (2.307332) is not a real number.
The error happens at the call to >= and one argument is a list of a number, not a number.
Since you try to extract the number from a list, does that extract work?
We see that you call CDR. CDR of a list returns a list. So there is the error. You need to extract the number from the list.
Btw., CLISP has commands like help, where, backtrace, ... to further investigate the problem. Just type help and return, without anything else, and you see a list of commands.

Create a variable name from a string in Lisp

I'm trying to take a string, and convert it into a variable name. I though (make-symbol) or (intern) would do this, but apparently it's not quite what I want, or I'm using it incorrectly.
For example:
> (setf (intern (string "foo")) 5)
> foo
5
Here I would be trying to create a variable named 'foo' with a value of 5. Except, the above code gives me an error. What is the command I'm looking for?
There are a number of things to consider here:
SETF does not evaluate its first argument. It expects a symbol or a form that specifies a location to update. Use SET instead.
Depending upon the vintage and settings of your Common Lisp implementation, symbol names may default to upper case. Thus, the second reference to foo may actually refer to a symbol whose name is "FOO". In this case, you would need to use (intern "FOO").
The call to STRING is harmless but unnecessary if the value is already a string.
Putting it all together, try this:
> (set (intern "FOO") 5)
> foo
5
Use:
CL-USER 7 > (setf (SYMBOL-VALUE (INTERN "FOO")) 5)
5
CL-USER 8 > foo
5
This also works with a variable:
CL-USER 11 > (let ((sym-name "FOO"))
(setf (SYMBOL-VALUE (INTERN sym-name)) 3))
3
CL-USER 12 > foo
3
Remember also that by default symbols are created internally as uppercase. If you want to access a symbol via a string, you have to use an uppercase string then.

Resources