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))
Related
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\"}]"
|#
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"))
I am trying to make my own length/2 function(which allows you to find the length of a list) in lisp and am having an issue.
If I were to program this in java I would create a global index variable
that = 0
Then in the method I would do
if(list.equal(null))
{
return index;
}
else
{
index++;
return functioname(tail of list) ;
}.
Obviously this is not actual java syntax but I am just trying to relay the logic I want to apply in lisp.
My main issue is that ifs in lisp only allow you to do
if test expression
then do something
else
do something else
while I am trying to do
if test expression
then do something
else
do 2x something
Is there a way I can accomplish this in lisp or is there a better way to go about this problem?
Do it recursively:
len(list):
if list is null
return 0
else
remove first_item from list
return 1 + len(list)
(define (length items)
(if (null? items)
0
(+ 1
(length (cdr items)))))
(length (list 1 2 3))
3
Or use set!:
(define count 0)
(define (length items)
(when (not (null? items))
(set! count (+ count 1))
(length (cdr items))))
(length (list 1 2 3 4 5))
count
5
Scheme has the special operator begin (the Common Lisp equivalent is progn) that lets you group expressions which are executed in sequence, and returns the last one.
(if (null? items)
0
(begin (set! index (+ 1 index))
(my-length (cdr items))
index))
If the if expression returns nil under the false condition, then you can also use when (as in Rahn's answer) which is a bit more compact.
That said, having a global variable, or any variable at all, whose value gets changed (which is the purpose of a variable) is not the Lisp/recursive way of doing things. (Global variables are not a good thing in any language.) Rahn's first example is the only way any experienced Lisp programmer would do it.
In my example above, the (set! index (+ 1 index)) and index)) lines, and the global variable index are completely unnecessary if you add the 1 to the (my-length (cdr items)). If the list is empty, the length is zero; otherwise, the length is 1 + the length of the tail of the list.
I have this code:
(define (countHearts cards)
(let* ([count 0])
(map (λ(x)
(match x
[(hearts number) (add1 count)]
[_ #f])) cards))
count)
Where cards is a list of elements in this format "(hearts number)" And when I use:
(countHearts '( (hearts 1) (hearts 2)))
It returns (the answer should be 2):
#<procedure:count>
All I want is that my code counts the number of "(heart number)" (a type previously defined) that I have in a list, but I keep getting that answer. Does anybody have an idea? I have tried other options besides add1 like
!set count (+ count 1)
But the result is the same.
Try:
(define (count-hearts cards)
(for/sum ([card cards])
(match card
[(list 'hearts n) 1]
[_ 0])))
why your code doesn't work
(add1 count) adds 1 to count but throws the result away; you need to set! count to the result of (add1 count)
You had a closing parenthesis too many so your variable count got out of scope and you returned the build-in procedure count - count needs to be returned inside the let* or let expression (I use let since that's sufficient here)
FWIW, both your and #soegaard's code don't work for me and return "match: syntax error in pattern"; I modified the match expression to (list 'hearts _)
So the code becomes:
(define (countHearts cards)
(let ([count 0])
(map (λ(x)
(match x
[(list 'hearts _) (set! count (add1 count))]
[_ #f]))
cards)
count))
then
> (countHearts '((hearts 1) (hearts 2)))
2
alternative
You could use the build-in count procedure:
(define (countHearts cards)
(count (lambda (e) (eq? (car e) 'hearts))
cards))
I'm supposed to define the function n! (N-Factorial). The thing is I don't know how to.
Here is what I have so far, can someone please help with this? I don't understand the conditionals in Racket, so an explanation would be great!
(define fact (lambda (n) (if (> n 0)) (* n < n)))
You'll have to take a good look at the documentation first, this is a very simple example but you have to understand the basics before attempting a solution, and make sure you know how to write a recursive procedure. Some comments:
(define fact
(lambda (n)
(if (> n 0)
; a conditional must have two parts:
; where is the consequent? here goes the advance of the recursion
; where is the alternative? here goes the base case of the recursion
)
(* n < n))) ; this line is outside the conditional, and it's just wrong
Notice that the last expression is incorrect, I don't know what it's supposed to do, but as it is it'll raise an error. Delete it, and concentrate on writing the body of the conditional.
The trick with scheme (or lisp) is to understand each little bit between each set of brackets as you build them up into more complex forms.
So lets start with the conditionals. if takes 3 arguments. It evaluates the first, and if that's true, if returns the second, and if the first argument is false it returns the third.
(if #t "some value" "some other value") ; => "some value"
(if #f "some value" "some other value") ; => "some other value"
(if (<= 1 0) "done" "go again") ; => "go again"
cond would work too - you can read the racket introduction to conditionals here: http://docs.racket-lang.org/guide/syntax-overview.html#%28part._.Conditionals_with_if__and__or__and_cond%29
You can define functions in two different ways. You're using the anonymous function approach, which is fine, but you don't need a lambda in this case, so the simpler syntax is:
(define (function-name arguments) result)
For example:
(define (previous-number n)
(- n 1))
(previous-number 3) ; => 2
Using a lambda like you have achieves the same thing, using different syntax (don't worry about any other differences for now):
(define previous-number* (lambda (n) (- n 1)))
(previous-number* 3) ; => 2
By the way - that '*' is just another character in that name, nothing special (see http://docs.racket-lang.org/guide/syntax-overview.html#%28part._.Identifiers%29). A '!' at the end of a function name often means that that function has side effects, but n! is a fine name for your function in this case.
So lets go back to your original question and put the function definition and conditional together. We'll use the "recurrence relation" from the wiki definition because it makes for a nice recursive function: If n is less than 1, then the factorial is 1. Otherwise, the factorial is n times the factorial of one less than n. In code, that looks like:
(define (n! n)
(if (<= n 1) ; If n is less than 1,
1 ; then the factorial is 1
(* n (n! (- n 1))))) ; Otherwise, the factorial is n times the factorial of one less than n.
That last clause is a little denser than I'd like, so lets just work though it down for n = 2:
(define n 2)
(* n (n! (- n 1)))
; =>
(* 2 (n! (- 2 1)))
(* 2 (n! 1))
(* 2 1)
2
Also, if you're using Racket, it's really easy to confirm that it's working as we expect:
(check-expect (n! 0) 1)
(check-expect (n! 1) 1)
(check-expect (n! 20) 2432902008176640000)