英文:
Iterate over plist and set value per key
问题
如何遍历 plist,提示每个键的值,并将该值填入 plist 中?
我有一个项目属性列表的“骨架”。
(defconst project-properties
'(:number nil
:place nil
:location nil))
我复制这个列表并填入值,以便保留一个骨架列表并有填充后的列表以进一步处理。
我已经成功为 alist 完成了这个操作,但无法更改功能以使其与 plist 一起工作。
(defun project-prompt-properties-alist ()
"Prompt for project properties and return them"
(let ((properties (copy-alist project-properties)))
(cl-loop for (prop . val) in properties
do (setf (alist-get prop properties) (read-string (format "请输入 %s: " prop))))
properties))
英文:
How can I iterate over a plist, prompt for each key a value and fill in said value into the plist?
I have 'the skeleton' of a list of properties for my projects
(defconst project-properties
'(:number nil
:place nil
:location nil))
I copy this list and fill in the values so I keep a skeleton list and have the filled in list to process it further.
I managed to do it for an alist, but am unable to change the functionality to let it work with plists.
(defun project-prompt-properties-alist ()
"Prompt for project properties and return them"
(let ((properties (copy-alist project-properties)))
(cl-loop for (prop . val) in properties
do (setf (alist-get prop properties) (read-string (format "Geef %s: " prop))))
properties))
答案1
得分: 3
Common Lisp和Elisp都允许你使用on
来循环遍历列表,它会迭代列表的连续尾部,而不是使用in
来迭代列表的连续元素。例如:
CL-USER> (loop for tail on project-properties
do (format t "~A~%" tail))
(NUMBER NIL PLACE NIL LOCATION NIL)
(NIL PLACE NIL LOCATION NIL)
(PLACE NIL LOCATION NIL)
(NIL LOCATION NIL)
(LOCATION NIL)
(NIL)
你还可以使用by
关键字来在每次迭代时减少输入列表的两个元素,而不是一个:
CL-USER> (loop for tail on project-properties by #'cddr
do (format t "~A~%" tail))
(NUMBER NIL PLACE NIL LOCATION NIL)
(PLACE NIL LOCATION NIL)
(LOCATION NIL)
你可以使用解构来获取每个尾部的前两个元素:
CL-USER> (loop for (prop val) on project-properties by #'cddr
do (format t "~A -> ~A~%" prop val))
NUMBER -> NIL
PLACE -> NIL
LOCATION -> NIL
这些特性在Elisp中也适用。你可以像这样编写Elisp中的project-prompt-properties-plist
函数:
(defun project-prompt-properties-plist ()
"Prompt for project properties and return them"
(let ((properties (copy-sequence project-properties)))
(cl-loop for (prop val) on properties by #'cddr
do (plist-put properties prop (read-string (format "Geef %s: " prop))))
properties))
(Note: The provided code uses HTML entities for characters like "
, >
, and &
for formatting purposes, but these should be replaced with their actual characters in the code.)
英文:
Both Common Lisp and Elisp allow you to loop over a list using on
which iterates on successive tails of the list, instead of in
which iterates on successive elements of the list. For example:
CL-USER> (loop for tail on project-properties
do (format t "~A~%" tail))
(NUMBER NIL PLACE NIL LOCATION NIL)
(NIL PLACE NIL LOCATION NIL)
(PLACE NIL LOCATION NIL)
(NIL LOCATION NIL)
(LOCATION NIL)
(NIL)
You can further use the by
keyword to reduce the input list by two elements instead of one on each iteration:
CL-USER> (loop for tail on project-properties by #'cddr
do (format t "~A~%" tail))
(NUMBER NIL PLACE NIL LOCATION NIL)
(PLACE NIL LOCATION NIL)
(LOCATION NIL)
You can use destructuring to take the first two elements of each tail:
CL-USER> (loop for (prop val) on project-properties by #'cddr
do (format t "~A -> ~A~%" prop val))
NUMBER -> NIL
PLACE -> NIL
LOCATION -> NIL
These features work the same in Elisp. You should be able to write project-prompt-properties-plist
for Elisp like this:
(defun project-prompt-properties-plist ()
"Prompt for project properties and return them"
(let ((properties (copy-sequence project-properties)))
(cl-loop for (prop val) on properties by #'cddr
do (plist-put properties prop (read-string (format "Geef %s: " prop))))
properties))
答案2
得分: 1
如果您想收集用户输入的一组属性,您可以直接使用该列表来构建 plist:
```lisp
(loop :for property :in '(:number :place :location)
:collect property
:collect (read-query-whatever property))
或者使用 alist:
(loop :for property :in '(:number :place :location)
:collect (cons property
(read-query-whatever property)))
如果您想要更新用户可能不想更改的属性,那么您也可以像您所示的骨架想法一样遍历给定的 plist:
(loop :for (property value) :on '(:number 23 :place nil :location "moon") :by #'cddr
:collect property
:collect (read-query-whatever property value))
或者使用 alist:
(loop :for (property . value) :in '((:number . 23) (:place . nil) (:location "moon"))
:collect (cons property
(read-query-whatever property value)))
所有这些都是逐步构建新列表,而不是首先复制然后更新它。
<details>
<summary>英文:</summary>
If you want to collect user input for a list of properties, you can use that list directly to build the plist:
```lisp
(loop :for property :in '(:number :place :location)
:collect property
:collect (read-query-whatever property))
or the alist:
(loop :for property :in '(:number :place :location)
:collect (cons property
(read-query-whatever property)))
If you want to update properties that the user might want to leave unchanged, then you can also go over the given plist as you showed with the skeleton idea:
(loop :for (property value) :on '(:number 23 :place nil :location "moon") :by #'cddr
:collect property
:collect (read-query-whatever property value))
or the same with an alist:
(loop :for (property . value) :in '((:number . 23) (:place . nil) (:location "moon"))
:collect (cons property
(read-query-whatever property value)))
These all build a new list step by step, instead of first copying and then updating it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论