I need to find all nodes that are children of selected node. Graph is created like this:
(setq graf1 '((A(B C)) (B(D E)) (C (F G )) (D (H)) (E(I)) (F(J)) (G(J)) (H()) (I(J)) (J())))
So, all children from node B are (on first level) D,E, on 2nd H,I, third J.
Here's the code for finding first level children, but as i'm begineer in lisp i cant make it work for other ones.
(defun sledG (cvor graf obradjeni)
(cond ((null graf) '())
((equal (caar graf) cvor)
(dodaj (cadar graf) obradjeni))
(t(sledG cvor (cdr graf) obradjeni)))
(defun dodaj (potomci obradjeni)
(cond ((null potomci) '())
((member (car potomci) obradjeni)
(dodaj (cdr potomci) obradjeni )
(t(cons (car potomci)
(dodaj (cdr potomci) obradjeni) ))))
(setq graf1 '((A(B C)) (B(D E)) (C (F G )) (D (H)) (E(I)) (F(J)) (G(J)) (H()) (I(J)) (J())))
Using alexandria package:
(defvar *graf*
'((a (b c)) (b (d e)) (c (f g)) (d (h)) (e (i)) (f (j)) (g (j)) (h nil) (i (j)) (j nil)))
(defun descendants (tree label)
(let ((generation
(mapcan #'cadr
(remove-if-not
(alexandria:compose (alexandria:curry #'eql label) #'car)
tree))))
(append generation (mapcan (alexandria:curry #'descendants tree) generation))))
;; (D E H I J)
I believe, this is what you wanted to do. This will work for acyclic graphs, but it will recur "forever", if you have a cycle in it. If you wanted to add depth counter, you could add it as one more argument to descendants or in the last mapcan transform the resulting list by inserting the depth counter.
With depth included:
(defun descendants (tree label)
(labels ((%descendants (depth label)
(let ((generation
(mapcan #'cadr
(remove-if-not
(alexandria:compose
(alexandria:curry #'eql label) #'car)
tree))))
(append (mapcar (alexandria:compose
#'nreverse
(alexandria:curry #'list depth))
generation)
(mapcan (alexandria:curry #'%descendants (1+ depth))
generation)))))
(%descendants 0 label)))
;; ((D 0) (E 0) (H 1) (I 1) (J 2))
As I read it, the graph is a directed graph. So to find the children (directed edges) of the graph (in the example),
(defun children (node graph) (second (assoc node graph)))
then
(children 'b graf1) ; with graf1 from the OP
returns (D E). All you have to do then is to loop over the children, something like (very quick and dirty)
(defun all-children (node graph)
(let ((c (children node graph)))
(if (null c) nil
(union c (loop for x in c appending (all-children x graph))))))
This returns (J I H D E) as children of B.
Related
Hi I'm struggling with this problem, I don't know how to add the number of square tiles and incorporate that as a user input value, I only know how to increase the size of the tiles. So I can make the squares bigger but I can't increase the number of them. The main issue is alternating the square colors red and black and having user input of the board size. If you can show me with circles or anything else how to take user input to add more I'd appreciate any help, this is due in three days and I've been working on it for a while.
Edit: In my class we haven't learned for-loops in racket so if there's an iterative/recursive way that would help me out.
Here's my code with multiple attempts:
#lang slideshow
(define (square n) (filled-rectangle n n))
(define (redblock n) (colorize(square) "red"))
(define (blackblock n) (colorize(square) "black"))
;slideshow
(define (series n)
[hc-append (* square n)]) ; contract violation, expected: number?, given: #<procedure:square>
;slideshow
(define (rb-series mk)
(vc-append
(series [lambda (sz) (colorize (mk sz) "red")])
(series [lambda (sz) (colorize (mk sz) "black")])))
(define (checker p1 p2) ;makes 2x2
(let ([p12 (hc-append p1 p2)]
[p21 (hc-append p2 p1)])
(vc-append p12 p21)))
(define (four p) ;can we get the parameter of this as any number instead of the shape?
(define two-p (hc-append p p))
(vc-append two-p two-p))
(define (checkerboard n sz)
(let* ([redblock (colorize(square sz)"red")]
[blackblock (colorize(square sz)"black")])
(define (blackred-list n)
;(define (string lst)) ;is there a way to construct an empty string to add to?
(for ([i n])
(if (even? i)
(hc-append blackblock)
(else
(hc-append (redblock)))))) ; this else part throws an error saying no hc-append
(define (redblack-list n)
(for ([i n])
(if (even? i)
(hc-append redblock)
(else (hc-append blackblock))))) ;another else with the same issue
(define (row-list n)
(for ([i n])
(if (even? i)
(vc-append blackred-list)
(else
(vc-append redblack-list)))))
(checkerboard 5 20))) ;this is just to test it, but how would I get user input?```
Let's break it down step by step:
Define function named checkerboard:
(define (checkerboard n sz) ...
With local definitions of redblock and blackblock...
(let ([redblock (colorize (filled-rectangle sz sz) "red")]
[blackblock (colorize (filled-rectangle sz sz) "black")])
With function blackred-list (I used letrec for recursive local definitions)...
(letrec ([blackred-list
(lambda (m) (cond ((zero? m) '())
((even? m) (cons blackblock (blackred-list (sub1 m))))
(else (cons redblock (blackred-list (sub1 m))))))]
With function redblack-list, which is very similar to blackred-list, so I am leaving that as work for you.
With function row-list:
[row-list (lambda (m) (map (lambda (i) (apply hc-append (reverse
(if (even? i)
(blackred-list m)
(redblack-list m)))))
(range m)))]
Then write (apply vc-append (row-list n)) inside letrec.
User input isn't mentioned in task, because you will just call (checkerboard 6 15) (or any other test) in REPL, but you surely can do this:
> (checkerboard (read) (read))
If one can confidently write and assemble small functions then the suggestions in
the exercise may be all one needs to produce a solution. But if this is a skill
that one is learning, then following a systematic design method may
help that learning process.
The design method here is HtDF (How to Design Functions): write down stub with signature and purpose, examples, and template, then edit the template to produce the required function.
(This answer uses characters to stand for blocks -- substitute eg hc-append for list->string for images)
(define redblock #\r)
(define blackblock #\b)
#;
(define (blackred-list m) ;; Natural -> ListOfBlock ; *stub* ;; *signature*
;; produce list of m alternating blocks (last one red) ; *purpose statement*
empty) ; *stub body* (valid result)
(check-expect (blackred-list 0) empty ) ; *minimal example*
#;
(define (fn n) ; *template*
(cond ;
[(zero? n) ... ] ;
[else (.... n (fn (- n 1))) ])) ;
(check-expect (blackred-list 1) (list redblock) ) ; *examples* to guide .... edit
(check-expect (blackred-list 2) (list blackblock redblock) )
(define (blackred-list m) ;; Natural -> ListOfBlock ; (edit template)
;; produce list of m alternating blocks (last one red)
(cond
[(zero? m) empty ]
[else (cons
(if (even? m)
blackblock
redblock)
(blackred-list (- m 1))) ]))
(check-expect (blackred-list 3) (list redblock blackblock redblock) )
(define (redblack-list m) ;; Natural -> ListOfBlock
;; produce list of m alternating blocks (last one black)
(cond
[(zero? m) empty ]
[else (cons
(if (even? m)
redblock
blackblock)
(redblack-list (- m 1))) ]))
(check-expect (redblack-list 3) (list blackblock redblock blackblock) )
#;
(define (row-list m) ;; Natural -> ListOfString ; *stub*
;; produce list of m alternating strings of blocks (last one ends in red)
empty)
(check-expect (row-list 0) empty) ; *examples* (same template)
(check-expect (row-list 1) (list "r") )
(check-expect (row-list 2) (list "rb" "br") )
(define (n-strings-of-length m n) ;; Natural Natural -> ListOfString
;; produce list of n alternating length m strings of blocks (last one ends in red)
(cond
[(zero? n) empty ]
[else (cons
(if (even? n)
(list->string (redblack-list m))
(list->string (blackred-list m)))
(n-strings-of-length m (- n 1))) ]))
(define (row-list m) ;; Natural -> ListOfString
;; produce list of m alternating length m strings of blocks (last one ends in red)
(n-strings-of-length m m))
(define (display-rows los) ;; ListOfString -> ; (from natural list recursion template)
;; display los, one element per line
(cond
[(empty? los) (void) ]
[else (begin
(display (car los))
(newline)
(display-rows (cdr los))) ]))
(define (checkerboard m) ;; Natural ->
;; display checkerboard with side m
(display-rows (row-list m)))
Welcome to DrRacket, version 8.4 [cs].
Language: Advanced Student.
All 8 tests passed!
>
The functions can now be reordered to produce the solution in specified local form:
(define redblock #\r)
(define blackblock #\b)
(define (checkerboard m) ;; Natural ->
;; display checkerboard with side m
(local [
(define (blackred-list m) ;; Natural -> ListOfBlock
;; produce list of m alternating blocks (last one red)
(cond
[(zero? m) empty ]
[else (cons
(if (even? m)
blackblock
redblock)
(blackred-list (- m 1))) ]))
(define (redblack-list m) ;; Natural -> ListOfBlock
;; produce list of m alternating blocks (last one black)
(cond
[(zero? m) empty ]
[else (cons
(if (even? m)
redblock
blackblock)
(redblack-list (- m 1))) ]))
(define (n-strings-of-length m n) ;; Natural Natural -> ListOfString
;; produce list of n alternating length m strings of blocks (last one ends in red)
(cond
[(zero? n) empty ]
[else (cons
(if (even? n)
(list->string (redblack-list m))
(list->string (blackred-list m)))
(n-strings-of-length m (- n 1))) ]))
(define (row-list m) ;; Natural -> ListOfString
;; produce list of m alternating length m strings of blocks (last one ends in red)
(n-strings-of-length m m))
(define (display-rows los) ;; ListOfString ->
;; display los, one element per line
(cond
[(empty? los) (void) ]
[else (begin
(display (car los))
(newline)
(display-rows (cdr los))) ])) ])
(display-rows (row-list m)))
Welcome to DrRacket, version 8.4 [cs].
Language: Advanced Student.
> (checkerboard 5)
rbrbr
brbrb
rbrbr
brbrb
rbrbr
>
The task is: for given list of elements and X element, remove an element after X if it is not equal to X. Example: (a 8 2 a a 5 a) X=a, expecting (a 2 a a a).
I have code that removes an element before X, so it gives me (a 8 a a a) instead. How do I fix it?
(defun purgatory (n w)
(cond ((null w) nil)
((and (eq (cadr w) n) (not (eq (car w) (cadr w)))) (purgatory n (cdr w)))
((cons (car w) (purgatory n (cdr w))))))
You can use the destructuring of for on clauses in loop:
(defun purgatory (list x)
(cons (first list)
(loop :for (a b) :on list
:unless (and (eql a x)
(not (eql b x)))
:collect b)))
I think you are on the right lines with a recursive algorithm. I think that the algorithm works better as a tail-optimised recursion. You take an in-list and an X, and build up an out-list. The output is reversed, and so reverse needs to be applied at the end, thus:
(defparameter my-list '(a 8 2 a a 5 a))
(defun remove-after (in-list X &optional (out-list '()) (last '()))
(if (null in-list)
(reverse out-list)
(if (and (eql last X) (not (eql (car in-list) X)))
(remove-after (cdr in-list) X out-list (car in-list))
(remove-after (cdr in-list) X (cons (car in-list) out-list) (car in-list))
)))
; (A 2 A A A)
As for the non-tail algorithm, I think this does it:
(defun purgatory (n w)
(cond ((null w) nil)
((and (eq (car w) n) (not (eq n (cadr w)))) (cons (car w) (purgatory n (cddr w))))
(t (cons (car w) (purgatory n (cdr w))))
))
; (A 2 A A A)
So, if the first element is n and the next is not n, then add n at the front of the algorithm, but skip cddr the next element. Otherwise, add the first element to the front of the algorithm, no skip cdr.
NB: since you've defined the problem in terms of X, I think this should be one of your parameters, not n
So I have to count the occurrence of a word(or character, to be more specific) in a list in lisp. For example, the input:
(freq 'c '(a c c c c (c c c e)))
should produce a count of 7, since there are 7 c's in the list argument. The code I have is the following but it does not work. I can count the 4 c's that are base elements and the 3 c's that are in the sublist, but I dont know how to add them together. Also, I'm using only primitive data types.
(defun freq (a L)
(cond
((null L) 0)
((listp (car L)) ( (freq a (car L))) ((freq a (cdr L))))
((eq a (car L))(+ 1 (freq a (cdr L))))
(t ((freq a (cdr L))))))
If it's a character then it's should be written with this prefix -> #\
and the sequence would be a string so there is no need recursion here.
(count #\c "(a c c c c (c c c e))") => 7
What you're dealing with in your example is symbol (with a single quote) through a list which contains other symbols or cons. So if you need to count all the same symbol you could write something like that :
(defparameter *nb* 0)
(defun look-deeper (test seq)
(loop for i in seq do
(compare test i)))
(defun compare (test item)
(let ((type (type-of item)))
(case type
(symbol (when (eql test item) (incf *nb*)))
(cons (look-deeper test item)))))
(look-deeper 'c '(a c c c c (c c c e))) => NIL
*nb* => 7
Or something better..
(defun count-occurences (obj lst)
(let ((acc 0))
(labels ((test (obj-2)
(eq obj obj-2)))
(dolist (x lst)
(if (consp x)
(let ((sample (remove-if-not #'test x)))
(if sample
(incf acc (length sample))))
(if (eq x obj)
(incf acc 1)))))
acc))
We could create a function that takes an obj to test and a lst as the argument and create a local accumulator to keep track of how many times the obj occurs in the list. Then we could create a local function that tests to see if the obj we pass to it is eq to the obj passed as an argument to the global function (also note that if you are working with strings you might want to use string-equal or equal because eq will not work since they are not the same object, but eq will work with symbols which you used in your example). We can then iterate through the list, and if the element in the list is a cons we can use remove-if-not to remove any element that doesn't pass our test (is not eq to the obj), and based on the length of the list increment our accumulator accordingly. If it is not a cons and is eq to our obj we will also increment the accumulator, then we can return the value of our accumulator.
And if we test it:
CL-USER> (count-occurences 'c '(a c c c c (c c c)))
7
Your logic is actually correct, there are just some small mis-parenthesis problems in your code. The only change you need for your code to work is to change you listp and t clauses from
((listp (car L)) ( (freq a (car L))) ((freq a (cdr L))))
into
((listp (car L)) (+ (freq a (car L)) (freq a (cdr L))))
and from
(t ((freq a (cdr L))))
into
(t (freq a (cdr L)))
Then evaluating your function works just as you expect:
(defun freq (a L)
(cond
((null L) 0)
((listp (car L)) (+ (freq a (car L)) (freq a (cdr L))))
((eq a (car L))(+ 1 (freq a (cdr L))))
(t (freq a (cdr L)))))
(freq 'c '((a (c f c)) c c c (c c (d c f (c 8 c) c) e))) ; => 11 (4 bits, #xB, #o13, #b1011)
I am learning Lisp. I have implemented a Common Lisp function that merges two strings that are ordered alphabetically, using recursion. Here is my code, but there is something wrong with it and I didn't figure it out.
(defun merge (F L)
(if (null F)
(if (null L)
F ; return f
( L )) ; else return L
;else if
(if (null L)
F) ; return F
;else if
(if (string< (substring F 0 1) (substring L 0 1)
(concat 'string (substring F 0 1)
(merge (substring F 1 (length F)) L)))
(
(concat 'string (substring L 0 1)
(merge F (substring L 1 (length L)) ))
))))
Edit :
I simply want to merge two strings such as the
inputs are string a = adf and string b = beg
and the result or output should be abdefg.
Thanks in advance.
Using string< is an overkill, char< should be used instead, as shown by Kaz. Recalculating length at each step would make this algorithm quadratic, so should be avoided. Using sort to "fake it" makes it O(n log n) instead of O(n). Using concatenate 'string all the time probably incurs extra costs of unneeded traversals too.
Here's a natural recursive solution:
(defun str-merge (F L)
(labels ((g (a b)
(cond
((null a) b)
((null b) a)
((char< (car b) (car a))
(cons (car b) (g a (cdr b))))
(t (cons (car a) (g (cdr a) b))))))
(coerce (g (coerce F 'list) (coerce L 'list))
'string)))
But, Common Lisp does not have a tail call optimization guarantee, let alone tail recursion modulo cons optimization guarantee (even if the latter was described as early as 1974, using "Lisp 1.6's rplaca and rplacd field assignment operators"). So we must hand-code this as a top-down output list building loop:
(defun str-merge (F L &aux (s (list nil)) ) ; head sentinel
(do ((p s (cdr p))
(a (coerce F 'list) (if q a (cdr a)))
(b (coerce L 'list) (if q (cdr b) b ))
(q nil))
((or (null a) (null b))
(if a (rplacd p a) (rplacd p b))
(coerce (cdr s) 'string)) ; FTW!
(setq q (char< (car b) (car a))) ; the test result
(if q
(rplacd p (list (car b)))
(rplacd p (list (car a))))))
Judging by your comments, it looks like you're trying to use if with a series of conditions (like a series of else ifs in some other languages). For that, you probably want cond.
I replaced that if with cond and cleaned up some other errors, and it worked.
(defun empty (s) (= (length s) 0))
(defun my-merge (F L)
(cond
((empty F)
(if (empty L)
F
L))
((empty L)
F)
(t
(if (string< (subseq F 0 1) (subseq L 0 1))
(concatenate 'string (subseq F 0 1) (my-merge (subseq F 1 (length F)) L))
(concatenate 'string (subseq L 0 1) (my-merge F (subseq L 1 (length L))))))))
Your test case came out as you wanted it to:
* (my-merge "adf" "beg")
"abdefg"
There were quite a few good answers, so why would I add one more? Well, the below is probably more efficient then the other answers here.
(defun merge-strings (a b)
(let* ((lena (length a))
(lenb (length b))
(len (+ lena lenb))
(s (make-string len)))
(labels
((safe-char< (x y)
(if (and x y) (char< x y)
(not (null x))))
(choose-next (x y)
(let ((ax (when (< x lena) (aref a x)))
(by (when (< y lenb) (aref b y)))
(xy (+ x y)))
(cond
((= xy len) s)
((safe-char< ax by)
(setf (aref s xy) ax)
(choose-next (1+ x) y))
(t
(setf (aref s xy) by)
(choose-next x (1+ y)))))))
(choose-next 0 0))))
(merge-strings "adf" "beg")
It is more efficient specifically in the sense of memory allocations - it only allocates enough memory to write the result string, never coerces anything (from list to string or from array to string etc.) It may not look very pretty, but this is because it is trying to do every calculation only once.
This is, of course, not the most efficient way to write this function, but programming absolutely w/o efficiency in mind is not going to get you far.
A recursive way to do it (fixed according to comment- other solutions can get an IF form as well).
(defun merge-strings (a b)
(concatenate 'string
(merge-strings-under a b)))
(defun merge-strings-under (a b)
(when (and
(= (length a)
(length b))
(> (length a) 0))
(append (if (string< (aref a 0) (aref b 0))
(list (aref a 0) (aref b 0))
(list (aref b 0) (aref a 0)))
(merge-strings-under (subseq a 1)
(subseq b 1)))))
Here's a iterative way to do it.
(concatenate 'string
(loop for i across "adf" for j across "beg" nconc (list i j)))
Note that these rely on building the string into a list of characters, then vectorizing it ( a string is a vector of characters).
You can also write a more C-esque approach...
(defun merge-strings-vector (a b)
(let ((retstr (make-array (list (+
(length a)
(length b)))
:element-type 'character)))
(labels ((merge-str (a b i)
(when (and
(= (length a)
(length b))
(/= i (length a)))
(setf (aref retstr (* 2 i)) (aref a i))
(setf (aref retstr (1+ (* 2 i))) (aref b i))
(merge-str a b (1+ i)))))
(merge-str a b 0)
retstr)))
Note that this one - unlike the other 2 - has side effects within the function. It also, imo, is more difficult to understand.
All 3 take varying numbers of cycles to execute on SBCL 56; each seems to take between 6K and 11K on most of my trials. I'm not sure why.
I have an implementation of BFS I got elsewhere and modified slightly, but I am having problems with its input.
It takes a graph, and will take it as '((a b c) (b c) (c d))
But my input I am giving it is a weighted graph... I know it's not useful for the BFS, but I use the weights farther down the line later. This input looks like
'(
(a (b 3) (c 1))
(b (a 3) (d 1))
(c (a 1) (d2) (e 2))
)
And so on.
My code:
(defun shortest-path (start end net)
(BFS end (list (list start)) net))
(defun BFS (end queue net)
(if (null queue)
nil
(expand-queue end (car queue) (cdr queue) net)))
(defun expand-queue (end path queue net)
(let ((node (car path)))
(if (eql node end)
(reverse path)
(BFS end
(append queue
(new-paths path node net))
net))))
(defun new-paths (path node net)
(mapcar #'(lambda (n)
(cons n path))
(cdr (assoc node net))))
I'm just not sure where I need to most likely modify it to accept the new style list, or make a help function to format it correctly?
You need to specify what the list that represents your graph means. Currently you have only given an example list.
When the graph has a syntax like:
graph = (node*)
node = (name nextnodename*)
name = SYMBOL
nextnodename = SYMBOL
Then a transformation function might be:
(defun convert-graph (graph)
(mapcar (lambda (node)
(destructuring-bind (name . nodes) node
(cons name (mapcar #'first nodes))))
graph))
or if you might need other extraction functions:
(defun convert-graph (graph &key (key #'first))
(mapcar (lambda (node)
(destructuring-bind (name . nodes) node
(cons name (mapcar key nodes))))
graph))
Example:
(convert-graph '((a (b 3) (c 1))
(b (a 3) (d 1))
(c (a 1) (d 2) (e 2)))
:key #'first)
((A B C) (B A D) (C A D E))
Now you might need to remove duplicate links. But this depends on the syntax and semantics of your graph description.