遍历 plist 并根据键设置值。

huangapple go评论68阅读模式
英文:

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 &#39;(:number :place :location)
      :collect property
      :collect (read-query-whatever property))

or the alist:

(loop :for property :in &#39;(: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 &#39;(:number 23 :place nil :location &quot;moon&quot;) :by #&#39;cddr
      :collect property
      :collect (read-query-whatever property value))

or the same with an alist:

(loop :for (property . value) :in &#39;((:number . 23) (:place . nil) (:location &quot;moon&quot;))
      :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.

huangapple
  • 本文由 发表于 2023年8月10日 22:53:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/76876921.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定