Turning DB information into JSON with keys? - json

I have a database that returns data as a tree like this:
'((7 "vince" "vince1#test.com" "space" "no value" 1)
(8 "vince" "vince2#test.com" "place" "no value" 1)
(9 "Smith" "Smith#gmail.com" "now" "no value" 1))
The second column is first name and the third column is email.
My goal is to return JSON key value pairs but im struggling
Here is what I have tried:
Function to get name and email from one list item
(defun get-name-&-emails-db1 (lst)
(if (null lst)
nil
(let* ((name (second lst))
(email (third lst)))
(cl-json:encode-json-to-string `((:name . ,name)(:email . ,email))))))
Map over data set
(mapcar #'get-name-&-emails-db1 (return-data-tree))
This returns a list of individual json blocks. But I want it to be ONE json block with all records.
What am I missing?
(ideally, I want to know how to do this without any additional libraries)
Thanks

I tried to encode a list of alists, and this is how it goes:
USER> (cl-json:encode-json
(list '(("a" . "0") ("b" . "1")) '(("a" . "2") ("b" . "3"))))
[{"a":"0","b":"1"},{"a":"2","b":"3"}]
If this is what you want to have, then you need to organize your data in Lisp first, then encode the whole list as JSON instead of formatting each entry individually.

Use mapcar, get the second and third element of each entry, and then call cl-json:encode-json-to-string on the result:
(let ((data '((7 "vince" "vince1#test.com" "space" "no value" 1)
(8 "vince" "vince2#test.com" "place" "no value" 1)
(9 "Smith" "Smith#gmail.com" "now" "no value" 1))))
(cl-json:encode-json-to-string
(mapcar (lambda (e) `((:name . ,(second e))(:email . ,(third e))))
data)))

Here I don't use comma, backquote, alists or plists, but simply: I create a list of hash-tables. I'm quite sure how a list and a hash table are rendered in JSON, so let's rework our data a bit to come back in known territories.
(loop for row in '((7 "vince" "vince1#test.com" "space" "no value" 1)
(8 "vince" "vince2#test.com" "place" "no value" 1)
(9 "Smith" "Smith#gmail.com" "now" "no value" 1))
with result = (list) ;; the list of hash-tables to encode.
for ht = (make-hash-table) ;; intermediary hash-table.
do (setf (gethash "name" ht)
(second row)
(gethash "email" ht)
(third row))
(push ht result)
finally (return (cl-json:encode-json-to-string result)))
;; =>
"[{\"name\":\"Smith\",\"email\":\"Smith#gmail.com\"},{\"name\":\"vince\",\"email\":\"vince2#test.com\"},{\"name\":\"vince\",\"email\":\"vince1#test.com\"}]"
I like Serapeum's dict:
;; replaces (for ht = (make-hash-table)) and the setf
for ht = (dict :name (second row)
:email (third row))

Answers were given. Just a general way to deal with alist and json:
(ql:quickload :yason)
(defparameter *data* '((7 "vince" "vince1#test.com" "space" "no value" 1)
(8 "vince" "vince2#test.com" "place" "no value" 1)
(9 "Smith" "Smith#gmail.com" "now" "no value" 1)))
(defparameter *scheme* '(:id :name :email :meta :value :count))
(defun pairing (keys values)
(loop for a in keys
for b in values
collect (cons (string-downcase (format nil "~A" a)) b)))
(defun alist-json (x &keys keys)
(with-output-to-string (*standard-output*)
(yason:encode-alist (pairing keys x))))
(defun list-json (l)
(format nil "[~{~A~^, ~}]" l))
(defun values-list-keys-json (values-list keys)
(list-json (mapcar (lambda (x) (alist-json x :keys keys)) values-list)))
(values-list-keys-json *data* *scheme*)
#|
=> "[{\"id\":7,\"name\":\"vince\",\"email\":\"vince1#test.com\",\"meta\":\"space\",\"value\":\"no value\",\"count\":1},
{\"id\":8,\"name\":\"vince\",\"email\":\"vince2#test.com\",\"meta\":\"place\",\"value\":\"no value\",\"count\":1},
{\"id\":9,\"name\":\"Smith\",\"email\":\"Smith#gmail.com\",\"meta\":\"now\",\"value\":\"no value\",\"count\":1}]"
|#
(defun second-third (l)
(subseq l 1 3))
(values-list-keys-json (mapcar #'second-third *data*) (second-third *scheme*))
#|
=> "[{\"name\":\"vince\",\"email\":\"vince1#test.com\"}, {\"name\":\"vince\",\"email\":\"vince2#test.com\"}, {\"name\":\"Smith\",\"email\":\"Smith#gmail.com\"}]"
|#

Related

Is there a Clojure macro equivalent to def?

I want to write a macro, sym-def, which has the same behavior as the special form def but uses (symbol "c"), say, as the first argument.
My first step was
(def (symbol "c") 4)
but this returned the error First argument to def must be a Symbol.
My second step was
(eval `(def ~(symbol "c") 4))
and this succeeded in defining c to be 4 in the global environment.
Why did my first step fail while the second step succeeded?
Finally, I attempted to write the desired macro
(defmacro sym-def [sym value] `(def ~sym ~value))
but this has a "bad" macroexpand
(macroexpand '(sym-def (symbol "c") 4)) => (def (symbol "c") 4)
so that
(sym-def (symbol "c") 4)
fails with the same error as my first step.
What is the correct way to write the macro?
def does not evaluate its first argument. Imagine the chaos if it did! You couldn't write
(def x 1)
because it would first try to evaluate x, and fail because x is not yet defined! Now, since it doesn't evaluate its arguments, clearly it makes sense that
(def (symbol "c") 4)
doesn't work, just as
(def 'c 4)
wouldn't. def requires its first argument to be a literal symbol. You don't have a literal symbol, so you can't use def.
But there is a lower-level mechanism to interact with the mappings in a namespace. In this case, you want clojure.core/intern:
(intern *ns* (symbol "c") 4)
intern is an ordinary function, so it evaluates all its arguments, meaning you can construct your var name in whatever crazy way you want. Then it adds to the given namespace a var mapping your symbol to its desired value.
A correct form for the macro you want to write is the following:
(defmacro sym-def [s v] `(def ~(eval s) ~v))
... or equivalently:
(defmacro sym-def [s v] (list `def (eval s) v))
You just need to evaluate the first argument inside the macro, because a macro's arguments are not evaluated when it is applied. If the only symbol-producing expressions you are going to use are calls to symbol, you may prefer the following macro:
(defmacro defsym [s v] (list `def (symbol s) v))
... and a companion to it:
(defmacro sym [s] (symbol s))
These macros translate a string or symbol to a symbol. Here are some examples of their use:
(defsym "the first natural number" 0)
;=> #'user/the first natural number
(sym "the first natural number")
;=> 0
(defsym pi 3.14159) ;same as: (def pi 3.14159)
;=> #'user/pi
(sym pi) ;same as: pi
;=> 3.14159
The variations given below might also be usefull:
(defmacro defsym* [s v] (list `def (symbol (eval s)) v))
(defmacro sym* [s] (symbol (eval s)))
They translate a string/symbol-producing expression to a symbol after evaluating it. Here are some examples of defsym*'s use:
(defsym* "abc" "xyz")
(defsym* (str \a \b \c) "xyz")
(defsym* (symbol "abc") "xyz")
(defsym* 'abc "xyz")
;all the previous are equivalent and what follows is valid for any of them
;=> #'user/abc
abc
;=> "xyz"
(defsym* abc 0)
;=> #'user/xyz
abc
;=> "xyz"
xyz
;=> 0

json-get function in lisp

In these day i'm working to a json parse in prolog and lisp.
yesterday with your help i finished the prolog project and now i need help again.
the funcion is always json-get but now in lisp.
this is the functin that i wrote:
(defun json-get (json_obj fields &optional n)
(let ((place (assoc fields json_obj :test 'string=)))
(if (null place)
n
(ns (second place) t)))
the behavior of the funtion should be the same of the prolog predicate.
for example if the input is:
CL-prompt> (defparameter x (json-parse "{\"nome\" : \"Arthur\",\"cognome\" : \"Dent\"}"))
X
CL-prompt> x
(json-obj ("nome" "Arthur") ("cognome" "Dent"))
the output should be:
CL-prompt> (json-get x "cognome")
"Dent"
insted, if the input is:
(json-get (json-parse
"{\"name\" : \"Zaphod\",
\"heads\" : [[\"Head1\"], [\"Head2\"]]}")
"heads" 1 0)
the output should be:
"Head2"
the function that i wrote is totally wrong?
P.S. for this project are forbidden functions like SET, SETQ, SETF e MULTIPLE-VALUE-SETQ and DO, DO*, DOTIMES, DOLIST e LOOP and DEFPARAMETER, DEFVAR e DEFCOSTANT inside a function
thanks guys
edit 1:
this is the description of this funcion,
a json-get function that accepts a JSON object
(represented in Common Lisp, as produced by the json_parse function) and a series of
"Fields", retrieve the corresponding object. A field represented by N (with N a number
greater than or equal to 0) represents an index of a JSON array.
edit 2 :
if i try to run json-get lisp answer me with:
Error: The variable PLACE is unbound.
You need to implement this recursively. You also need to distinguish JSON arrays (which are implemented as a list of elements prefixed with json-array) and JSON objects (which are implemented as an association list.
(defun json-get (json_obj fields)
(if (null fields) ; base case of recursion
json_obj
(let* ((cur-key (car fields))
(current (cond ((and (integerp cur-key)
(eq (car json_obj) 'json-array))
(nth (1+ cur-key) json_obj)) ; add 1 to skip over JSON-ARRAY
((and (stringp cur-key)
(eq (car json_obj) 'json-obj))
(second (assoc cur-key (cdr json_obj) :test #'string=))) ; Use CDR to skip over JSON-OBJ
(t (error "~S is not a JSON object or array or ~s is not appropriate key" json_obj cur-key)))))
(json-get current (cdr fields)))))
fields has to be a list of fields, so your second example would be:
(json-get (json-parse
"{\"name\" : \"Zaphod\",
\"heads\" : [[\"Head1\"], [\"Head2\"]]}")
'("heads" 1 0))
and the first example should be:
(json-get x '("cognome"))

lisp self-developed recursive reverse function

I have writte a list reverse function in lisp and I wanted to test it but I had an error and I couldn't solve it
the function and calling is below :
(defun myreverse (list)
(cond((null list) nil))
(cons (myreverse(cdr list) (car list))))
(myreverse '(1 2 3))
any help will be appreciated...
The arguments when you defun myreverse are (list), thus when you call it (myreverse '(1 2 3)) list gets bound to (1 2 3).
Since the list is not null you suddenly do (myreverse '(2 3) 1) and list gets bound to (2 3), but what do 1 get bound to? You have no more than one argument thus the call is invalid and warrants an error.
Hint1: There is a way to make optional arguments:
(defun test (a &optional (b 0) (c 0))
(+ a b c))
(test 10) ; ==> 10
(test 10 1 2) ; ==> 13
Hint2: You need to build a list not just pass a bare element. The passed list will be the tail of the next round until the every element is added.
The bad answer (or one of the bad answers):
(defun reverse (list)
(cond ((null list) list)
(t (append (reverse (cdr list)) (cons (car list) nil)))))
A better answer:
(defun reverse (list)
(reverse-aux list nil))
(defun reverse-aux (list result)
(cond ((null list) result)
(t (reverse-aux (cdr list) (cons (car list) result)))))
It's the basic example we use in comparison to the definition of 'append' in lessons to differentiate tail recursion.

Run a 3-arg (etc) function against a sequence of inputs

I'm trying to write some clojure which builds up a data-structure that will be valid clojure code as well. (note I'm not building a macro here: just a function that happens to return clojure code).
Here's my working bit:
(defn create-clause [ property operator value ]
(list (symbol operator) (symbol property) (symbol value))
)
(create-clause "b" "<" "5")
So this creates a 'clause' like this:
(< b 5)
And this works.
What I want to do is end up with something like this:
(and (= AccountType "current") (< Balance 0))
I can chain up a couple of clauses manually like this:
(list 'and (create-clause "a" "=" "current") (create-clause "b" "<" "0"))
Which results in:
(and (= a "current") (< b 0))
But I want a function that takes my 3-string arguments "property" "operator" "value" , creates the clause and results in a combined 'and' list of all the clauses which can be evaluated (assume the symbols are bound in a 'let' of course...)
EDIT: Got a bit closer but still no cigar....
Slightly refactored the func - so it now takes a single argument of a list , rather than 3 separate arguments:
(defn create-clause [ [ property operator value ] ]
(list (symbol operator) (symbol property) (symbol value))
)
(create-clause [ "b" "<" "5" ] )
Now using a loop/recur - and I can nearly get what I need:
(list 'and (loop [ input [ "a" "<" "10" , "b" "<" "5" ] output [] ]
(if (= (count input) 0) output
(recur (drop 3 input) (conj output (create-clause(take 3 input)))))))
The result of the above is:
(and [(< a 10) (< b 5)]) ; wrong - don't want that internal vector wrapper...
EDIT #2:
So I'm thinking I have accumulate the result somewhere in my loop - so I might was well stick to using the vector as above (but dropping the (list 'and...) ) - but then I should be able to apply something to the result of it which will have the effect of turning this something like this structure:
[ (= 1 1) (= 1 1) ]
Into this structure:
(and (= 1 1) (= 1 1))
But now I'm stuck again.....
EDIT #3:
Ok , I got there - I have ended up with an unholy mess - but at least it works and I can start refactoring now !
(conj (seq (loop [ input [ "AccountType" "=" "current" , "Balance" "<" 5 ] output [] ]
(if (= (count input) 0) output
(recur (drop 3 input) (conj output (create-clause(take 3 input))))))) 'and)
(and (= AccountType "current") (< Balance 5))
partition will chunk up a sequence into a certain size:
(def s (partition 3 (range 6)))
; s => ((0 1 2) (3 4 5))
A combination of map, partial and apply will let you call your method:
(defn reorder [a b c] (list b c a))
(def reordered (map (partial apply reorder) s))
; reordered => ((1 2 0) (4 5 3))
And top it all off with an and:
(conj reordered 'and)
; => (and (1 2 0) (4 5 3))

Isearch return t if found for loop function in Emacs Lisp

How to write a function where whenever a variable is found, it returns t (in order to allow a loop):
(setq x 1)
(while ("backward search for regexp "%x" equals true") ;where x is variable
(setq x (+ x 1))
(insert (concat "%" (int-to-string x)))
)
Example: If %1 (x=1) is found, it will add 1 to x. If %2 (x=2) is found, it will add 1 to x.
Let's say %3 is not found in a backward search, the while loop stops and "%" + "3" is inserted (%3).
I just don't understand the how to return true on a backward-search.
search-backward takes an optional third argument which, when non-nil, tells it to return nil in case the search was unsuccessful:
(setq x 1)
(while (search-backward (format "%%%d" x) nil t)
(setq x (1+ x)))
(insert (format "%%%d" x))
Now, if I try to understand what you really want to do (something like inserting at point the first %d string which doesn't appear before), then you might want to wrap the search inside a save-excursion form to avoid moving the point:
(setq x 1)
(while (save-excursion (search-backward (format "%%%d" x) nil t))
(setq x (1+ x)))
(insert (format "%%%d" x))
With help from Francesco
(defun Navi-insert-question ()
(interactive)
(setq x 1)
(while (save-excursion
(search-backward (concat comment-start " Question: " (int-to-string x)) nil t))
(setq x (+ 1 x)))
(insert (concat comment-start " Question: " (int-to-string x))))
It now results in being able to insert in R, for instance: "# Question: 1", when it exists above in the buffer it will insert "# Question: 2".