I'm new to Lisp and have no idea how to write this...
You give: ("Test" "TEST" "third" "the last")
You get: (("A" . "Test") ("B" . "TEST") ("C" . "third") ("D" . "the last"))
Function: (defun choices (&rest choices))
In C, I can just write a for for this, but Lisp can't +1 to string and loop doesn't have a counter, either... Could someone please give me a sample?
I would write something like this:
(defun choices (&rest choices)
(loop for i from 1 to 26
and item in choices
collect (cons (string (digit-char (+ 9 i) 36))
item)))
The above code has no error checking for more than 26 choices (and you
didn't specify how to handle them if it's not an error).
You could use CHAR-CODE and CODE-CHAR to "increment a character",
but the encoding they provide is not standardized (only some
properties of it are guaranteed). With DIGIT-CHAR in radix 36, we're
guaranteed to get the English alphabet (uppercase) for weights 10 to
35.
And of course, LOOP has a lot of things, including whatever counters you want.
You can concatenate two lists in the way you described by simply doing mapcar+cons:
(mapcar #'cons '("A" "B" "C" "D") '("Test" "TEST" "third" "the last"))
; => (("A" . "Test") ("B" . "TEST") ("C" . "third") ("D" . "the last"))
Since the second list is given, now the problem is only in generating the ABCD list. That can be achieved with loop and code-char:
(loop for i from 65 to 68 collect (string (code-char i)))
; => ("A" "B" "C" "D")
Combining those two into an answer and tailoring it to your specific problem should be easy now.
Related
I have a beginner question regarding “variable-expansion” while creating a quoted list.
Given the b/m code snippet, I want to set the variable content to hold the following list of cons cells (("a" . "b") ("c" . "d")).
(setq cvar "c")
;; Desperate try
(setq content '(("a" . "b")((symbol-value cvar) . "d"))
However, my problem is, that cvar does not get expanded, since the list is treated as it is. How can I achieve the intended result? Can somebody help me with that?
use backquote
(setq content `(("a" . "b") (,cvar . "d"))
or
(setq content (list '("a" . "b") (cons cvar "d"))
Say I have a list of cons cells like so:
(setq foo '(("a" . 1) ("b" . 2) ("c" . 3)))
And I'd like to retrieve the value of a particular cons cell by "key name". Is there a function that will let me do this?
E.g.
(get-by-key "a" foo) ;; => 1
Or something similar. Thanks in advance!
Such list is called an association list, or alist for short. Formally, an association list is a list of conses of a key and its associated value.
The assoc function is what you are looking for. It takes a key and an alist as its arguments and returns the first association for the key in the alist in terms of equal:
ELISP> (setq foo '(("a" . 1) ("b" . 2) ("c" . 3)))
(("a" . 1)
("b" . 2)
("c" . 3))
ELISP> (assoc "a" foo)
("a" . 1)
ELISP> (cdr (assoc "a" foo))
1
The assoc-string function is similar to the assoc function but specific to association lists whose keys are strings. In addition to a key and an alist, it can take another optional argument that makes the key comparison case-insensitive:
ELISP> (assoc-string "a" foo)
("a" . 1)
ELISP> (assoc-string "A" foo)
nil
ELISP> (assoc-string "A" foo t)
("a" . 1)
For the full list of association list-related functions, refer to GNU Emacs Lisp Reference Manual.
assoc-default lets you retrieve the value of a particular cons cell by "key name".
ELISP> (setq foo '(("a" . 1) ("b" . 2) ("c" . 3)))
(("a" . 1)
("b" . 2)
("c" . 3))
ELISP> (assoc-default "a" foo)
1
alist-get with the KEY and the ALIST as arguments gives you VALUE associated to the KEY.
E.g.,
(alist-get 'a '((a . 1) (b . 2) (c . 3)))
evaluates to 1.
Comparison is done with eq by default. But its full argument list is:
(alist-get KEY ALIST &optional DEFAULT REMOVE TESTFN)
So one can give:
A DEFAULT value that is returned if there is no match for KEY,
A flag REMOVE that removes the KEY VALUE pair if the new value is DEFAULT in
(setf (alist-get KEY ALIST DEFAULT t) DEFAULT)
A test function TESTFN for comparing KEY with the cars of ALIST
I have this association-list in Common Lisp:
(defvar base-list (list (cons 'a 0) (cons 2 'c)))
I have to call assoc when my argument is of type string.
For the pair (A . 0) I have to convert "a" to a symbol, and for the pair (2 . C) I have to convert "2" to a symbol. How can I do that?
This should work like this:
CL-USER 28 : 1 > (assoc (convert-string-to-symbol "a") base-list)
(A . 0)
CL-USER 28 : 1 > (assoc (convert-number-to-symbol "2") base-list)
(2 . C)
I tried using intern but got NIL:
CL-USER 29 : 1 > (assoc (intern "a") base-list)
NIL
The function you want is called read-from-string:
CL-USER> (read-from-string "a")
A
1
CL-USER> (read-from-string "2")
2
1
CL-USER>
Note that solutions based on using intern or find-symbol would not work for strings representing numbers (e.g., "2") on most implementations.
You were close with intern; you just had the case wrong. Try this:
> (assoc (intern "A") base-list)
(A . 0)
Note that here the name-as-string is capitalized.
Alternately, you could use find-symbol to look for an existing symbol by name:
> (assoc (find-symbol "A") base-list)
(A . 0)
The key here is that when you wrote your original defvar form, the reader read the string "a" and—by virtue of the current readtable case—converted the symbol name to be uppercase. Symbols with names of different case are not equal. It just so happens that at read time the reader is projecting what you wrote (lowercase) to something else (uppercase).
You can inspect the current case conversion policy for the current reader using the readtable-case function:
> (readtable-case *readtable*)
:UPCASE
To learn more about how the readtable case and the reader interact, see the discussion in section 23.1.2 of the Hyperspec.
Say I have a list with keywords:
'(("element1" :keyword1 "a" :keyword2 "b")
("element2" :keyword3 "c" :keyword4 "d")
("element3" :keyword2 "e" :keyword4 "f"))
Which functions can I use to find which list elements contain :keyword2 and find its value in each list? I'm trying to do this in Emacs Lisp but I think with the cl package I could possibly adapt a Common Lisp solution? I've tried to use the find function as illustrated here but to no avail (of course, after changing a few syntax elements to adapt the examples to Emacs Lisp).
(require 'cl)
(defvar *data* '(("element1" :keyword1 "a" :keyword2 "b")
("element2" :keyword3 "c" :keyword4 "d")
("element3" :keyword2 "e" :keyword4 "f")))
(find :keyword2 *data* :test #'find)
;;=> ("element1" :keyword1 "a" :keyword2 "b")
(getf (cdr (find :keyword2 *data* :test #'find)) :keyword2)
;;=> "b"
;; Above only finds the first match; to find all matches,
;; use REMOVE* to remove elements that do not contain the keyword:
(remove* :keyword2 *data* :test-not #'find)
;;=> (("element1" :keyword1 "a" :keyword2 "b")
;; ("element3" :keyword2 "e" :keyword4 "f"))
(mapcar (lambda (x) (getf (cdr x) :keyword2))
(remove* :keyword2 *data* :test-not #'find))
;;=> ("b" "e")
In Common Lisp, you would typically extract the values with destructuring-bind in this case, something like
(destructuring-bind (string &key keyword2 &allow-other-keys)
'("element1" :keyword1 "a" :keyword2 "b")
(list string keyword2)) ; or do anything with string and keyword2
should result in
("element1" "b")
In lisp, you would typically use a so-called associative list (or alist for short). It has the following form:
((key1 . value1) (key2 . value2) (key3 . value3))
There are a number of functions designed to work with alists, including assq and assoc, which return the dotted-pair, or nil.
Install dash list manipulation library (the GitHub link contains instructions). It contains multitude of helpful functions to achieve any goal. Suppose, your list above is named data, then you could:
(--find-indices (-elem-indices :keyword2 it) data) ; => (0 2)
(--map (cadr (--drop-while (not (eq :keyword2 it)) it)) data) ; => ("b" nil "e")
(--map-indexed (cons it-index ; => ((0 . "b") (1) (2 . "e"))
(cadr (--drop-while (not (eq :keyword2 it)) it))) data)
Is there any way by which cons can be implemented in Common LISP using list, append, first, rest etc?
In the following code
(defun my_list (&rest arguments)
`(,#arguments) ; Line 1
)
What does complete line 1 mean ?
First question: No, because cons is the building block for list and append, not the other way around. It is like trying to construct a brick out of houses.
Second question: The backquote syntax is explained in the CLHS (http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/sec_2-4-6.html).
Stylistic comments:
It is spelt "Common Lisp".
Do not use underscores to separate parts of names, but hyphens: my-list.
Do not let parentheses dangle around. Your snippet should be formatted like this:
(defun my-list (&rest arguments)
`(,#arguments)) ; Line 1
Using the backquote syntax outside of macros is usually not a good idea. In this case, it is completely superfluous:
(defun my-list (&rest arguments)
arguments)
Yes, you could in theory define cons in terms of list and append, like so:
(defun cons (car cdr) (append (list car) cdr))
I have the answer for the second question:
for the ,:
if my_symbol = 1
`(my_symbol 2 3) = (my_symbol 2 3), but with the ,:
`(,my_symbol 2 3) = (1 2 3)
The , evaluates the next symbol in a ` statement
Now for the # (which is a symbol, so it needs the , to be activated)
`(,#('a 'b 'c) ('d 'e 'f)) = ('a 'b 'c ('d 'e 'f) )
`(,#('a 'b 'c) ,#('d 'e 'f) ) = ('a 'b 'c 'd 'e 'f)
I hope these examples could help.
So the line 1 is simply extracting the arguments from a list and putting them into another one.
How about this?
(defun cons (a b) '(a . b))
Or, if you desperately need to use lists...
(defun cons (a b) (first (list '(a . b))))