Parsing a comma separated string in lisp - lisp

I am trying to parse a comma separated string with Common lisp with the function below. For (separate-on-comma "a,b,c") I would expect the output ("a" "b" "c") but instead I get ("c" "c" "c").
What do I miss here?
(defun separate-on-comma (line)
(loop
with fields = ()
with field = (make-array 0 :element-type 'character :adjustable t :fill-pointer 0)
for x across line
when (char= x #\,)
do (push field fields)
and do (setf (fill-pointer field) 0)
else
do (vector-push-extend x field)
finally
(push field fields)
(return fields)))
Thanks.

You are working only with one field array. That's okay. But you better copy it when you push it to the fields list variable. Use copy-seq.
Alternatively create a new field array once you pushed the old one onto the fields list.

Related

Why is a literal quoted list not the same as a list built by list constructors

(equal? '(1 2) (cons 1 2)) ; #f
Why exactly are these two not equivalent considering lists are just that — illusion built on top of cons cells.
(cons 1 2) does not create a proper list. It creates a cons cell with two elements, both are numbers.
A normal list is recursively defined as:
the empty list
or a cons cell with an object as the car and a list as the cdr.
In your call 2 is not a list, but a number. The second argument to cons must be a list to get a proper list.
(1 2)
in (1 2), the car element is a number, the cdr element is (2).
in (2), the car element is a number, the cdr element is (), the empty list.
() is the empty list.
Thus (1 2) is a list according to the definition above.
(cons 1 2) creates (1 . 2), which is not a list according to the definition above, since 2 is not a list.
A list is a chain of conses, with one cons for each element. So '(1 2) is equivalent to (cons 1 (cons 2 '())), which can be simplified to (list 1 2).
The literal equivalent to (cons 1 2) is '(1 . 2)
The question is tagged "racket" and "lisp", here I'm using the Common Lisp language but apart from details this is the same in Racket.
The literal list as read by the Lisp reader when reading the following text:
'(1 2)
can be built by evaluating the following form:
(cons 1 (cons 2 nil))
This is different from:
(cons 1 2)
Which also can be read using a special syntax, as follows:
'(1 . 2)

String addition assignment in lisp

I have a loop with a condition, based on which I decide whether I should append something to existing string or not.
In Python, it should look like (this is dummy code, just to show the idea):
result_str = ''
for item in range(5):
if item % 2 == 0:
result_str += str(item)
print(result_str)
Output: 024
So the question is: how can I perform addition assignment on strings (+=) in lisp?
String concatenation relies on the more general CONCATENATE function:
(concatenate 'string "a" "b")
=> "ab"
Since it considered verbose by some, you can find libraries that implement shorter versions:
(ql:quickload :rutils)
(import 'rutils:strcat)
And then:
(strcat "a" "b")
In order to assign and grow a string, you need to use SETF with an existing variable.
(let ((string ""))
(dotimes (i 5)
(when (evenp i)
(setf string (strcat string (princ-to-string i)))))
string)
A more idiomatic way in Lisp is to avoid string concatenation, but print in a stream which writes into a buffer.
(with-output-to-string (stream)
;; now, stream is bound to an output stream
;; that writes into a string. The whole form
;; returns that string.
(loop
for i from 0 below 5 by 2
do (princ i stream)))
=> "024"
Here above, stream is just the symbol used for naming the stream, you could use any other one, including *standard-output*, the special variable that represents current output stream. Doing so would make the enclosed code redirect its standard output to the string stream.
An alternative way to build the intermediate list is the following, where iota is a small utility in the alexandria library:
(delete-if #'oddp (alexandria:iota 5))
=> (0 2 4)
In order to produce a string, you can also use FORMAT, which has a directive that can iterate over lists:
(format nil "~{~a~}" '(0 2 4))
=> "024"
The nil stream destination represents a string destination, meaning (format nil ...) returns a string. Each directive starts with a tilde character (~), ~{ and ~} enclose an iteration directive; inside that block, ~a prints the value "aesthetically" (not readably).

Removing unwanted variables

Hi I am trying to remove unwanted variables from my list.
This is my function:
(defun remove-vars (list)
(loop for x in list do
(print x))))
I want to pass in this (get-vars '(A (NOT B) C))
and print out
A
B
C
but instead I am printing out
A
(NOT B)
C
Nil
is there a way to remove the parenthesis and the not from the list? Any guidance would be appreciated if the list was bigger with a b c d i would like to remove all instances of not and parenthesis. I guess what pseudocode would be to loop through check if "( ) or not exist in x" then delete those from the list
A simple solution is flatten the list and remove the NOT's like this:
(defun flatten (var-list)
(cond ((null var-list) nil)
((atom var-list) (list var-list))
(t (mapcan #'flatten var-list))))
(defun get-vars (var-list)
(remove 'NOT (flatten var-list)))
(get-vars '(A (NOT B) C))
Hope it helps
Your current code loops through and prints each element of the list, unconditionally.
When you pass it (A (NOT B) C), it is printing every element, one of which is the list (NOT B), and the loop is printing that list. The parentheses are output by the printer to represent that the element being printed is a list.
You need some logic to check if each element is something you'd like to not print, like the symbol NOT or nil, and recurse down when you see a something you want to examine further, such as a list.

How do I create a version of filter using map (racket ISL)

I am Tasked (in exercise 8) with creating a function in Intermediate Student Language (Racket) that receives a list of numbers and a list of lists of numbers; each list is the same length. Name the first list breakpoints and the second LoR (list of rows). This function should be defined using map and should filter each row in LoR so that only numbers larger than that the n'th row in LoR only contains values larger than the n'th value in breakpoints-- here is an example for clarity:
(define breakpoints (list 7 2 15))
(define LoR (list (list 3 25 13)
(list 1 2 11)
(list 22 4 8)))
would output...
(list (list 25 13) (list 11) (list 22))
Doing this without using map would be fine and I understand the problem in that sense, but I am having trouble figuring out how to use map. I was thinking recursively in the sense that if the list of rows is not empty, I would cons the (filtered first row) to the (recursive call of the function using the rest of breakpoints and LoR) as so:
(define (parallel-filter breakpoints LoR)
(cond((empty? breakpoints) empty)
(else (cons ...
(parallel-filter (rest breakpoints) (rest LoR))))))
However, I'm not sure how to replace the ellipse with a map statement that would make the function work correctly-- as I understand, map's first parameter must be a one-parameter function and I'm not sure how to use map for this purpose. How do I proceed?
edited to correct output
We can solve this problem by combining map and filter, but first bear in mind this:
You can't use just map, because it will always return a list of the same length as the original. For excluding some elements we must use filter (or alternatively: use foldr to implement our own version of filter)
map can receive more than one list as parameter, as long as its function receives enough parameters - one from each list
Your sample output is wrong for the first sublist
With all of the above in mind, here's one possible solution:
(define (parallel-filter breakpoints LoR)
(map (lambda (brk lst) ; `brk` is from `breakpoints` and `lst` is from `LoR`
(filter (lambda (ele) (> ele brk)) ; filter each sublist from `LoR`
lst))
breakpoints
LoR))
It works as expected:
(parallel-filter breakpoints LoR)
=> (list (list 25 13) (list 11) (list 22))

How to access "two" in (("one" . "two")) in elisp

I'm very new to elisp and I'm trying to adapt some existing code.
While looping over a table (generated by the orgmode function org-clock-get-table-data) I try the following:
((equal column "Project") (insert (cdr row)))
which yeilds the following in the Messages buffer:
cond: Wrong type argument: char-or-string-p, (#("Verify CalTime accruals for vacation/sick" 0 41
(fontified t org-category #("Admin" 0 5 (fontified t org-category "Admin" org-category-position 32
line-prefix nil wrap-prefix nil ...)) org-category-position 32 line-prefix #("*" 0 1 (face org-
hide)) wrap-prefix #(" " 0 4 (face org-indent)) ...)) nil 30 (("wps" . "Administration")))
The value that I want to insert is "Administration" so I try this
((equal column "Project") (insert (nth 4 row)))
which yeilds the following in the minibuffer
Wrong type argument, char-or-string-p, (("wps" . "Administration"))
Can someone tell me how I can insert the string "Administration"?
EDIT
Thanks Wes and Drew:
(cdar row)
Doing the above yields the first element of the complex list that I saw in the Messages buffer earlier:
Verify CalTime accruals for vaction/sick
row seems to be a complex list of lists:
((equal column "Project") (insert (car row))); yeilds ^B
((equal column "Project") (insert (cdr row)))
yields:
cond: Wrong type argument: char-or-string-p, (#("Verify CalTime accruals for vacation/sick" 0 41
(fontified t org-category #("Admin" 0 5 (fontified t org-category "Admin" org-category-position 32
line-prefix nil wrap-prefix nil ...)) org-category-position 32 line-prefix #("*" 0 1 (face org-
hide)) wrap-prefix #(" " 0 4 (face org-indent)) ...)) nil 30 (("wps" . "Administration")))
I think each "#" in the output above represents a list item. The fact that (nth 4 row) gives the error output shown above supports this and suggests that something like this might work:
((equal column "Project") (insert (nth 2 (nth 4 row))))
;yeilds wrong type argument, char-or-string-p, nil
So there is probably some function that I need to use to decode that 4th list item....
That 4th element is the orgmode property that has been assigned to the clocktable entry on the row we are parsing. This list of properties is defined in my .emacs:
(setq org-global-properties
;; WPS = Web Platform Services. Time tracking for Google Sheet begun with CalTime Migration
'(("wps_ALL".
"Administration
ASG-Consulting
Chanc-Office-Website
")))
Instead of the assoc + cdr combination, you can also use assoc-default:
ELISP> (assoc-default "one" '(("one" . "two")))
=> "two"
Note that lists of the form (("wps" . "Administration") ("foo" . "bar")) are typically "alists", and so you may need to handle the situation where there is more than one item in your list.
Read: C-hig (elisp) Association Lists RET
and also: (elisp) Dotted Pair Notation
You may obtain a keyed item from an alist with (assoc) or (assq) depending on the form of equality needed for the test. Equivalent strings are not equal objects in elisp, so in this case you want assoc rather than assq.
That gives you the entire (KEY . VALUE) form as a result, and you obtain the cdr of that as usual; hence:
(let ((my-alist '(("wps" . "Administration") ("foo" . "bar"))))
(cdr (assoc "wps" my-alist)))
yields: "Administration"
Lists are complex to think about in elisp. Until you've done enough of them that you stop thinking about them. Ha ha. But read up on the functions like car (picks the first element in a list) and cdr (picks the rest of the rest) to get started. And then you can chain things by combining letters in short sequences at least. So the answer you want is:
(cdar row)