두 속성 목록을 병합하는 기능?


11

다음과 같이 두 개의 속성 목록을 병합하는 표준 Elisp 라이브러리 함수를 찾지 못했습니다.

(setq pl nil)
(setq pl (plist-put pl 'key-1 'value-1))
(setq pl (plist-put pl 'key-2 'value-2))

로 무언가를 만들 수는 dolist있지만 일부 라이브러리의 기존 기능을 간과하지 않는지 확인하고 싶습니다.

주석을 기반으로 업데이트 :

  1. "많은 방법"의견에 대한 답변 :

나는 질문에 대해 다른 (그리고 유효한) 대답이 가능하기 때문에 그러한 기능이 없다고 상상할 수 있습니다.

예, 복제본을 병합하는 방법에 대한 질문이 있지만이를 해결하는 방법은 비교적 적습니다. 두 가지 일반적인 접근법이 있습니다. 첫째, 인수 순서는 중복을 해결할 수 있습니다. 예를 들어 Clojure의 merge 와 같이 가장 오른쪽에있는 승리 . 둘째, 병합은 Ruby의 merge 에서와 같이 사용자 제공 콜백 함수에 위임 할 수 있습니다.

어쨌든 다른 방법으로 여러 언어 표준 라이브러리가 병합 기능을 제공하는 것을 막을 수는 없습니다. 동일한 일반적인 주장을 정렬이라고 할 수 있지만 Elisp는 정렬 기능을 제공합니다.

  1. "정교하겠습니까?" / "찾고 싶은 행동을 정확하게 지정하십시오."

일반적으로 Elisp 커뮤니티가 사용하는 것에 개방적입니다. 특정 예를 원한다면 다음과 같은 예가 있습니다.

(a-merge-function '(k1 1) '(k2 2 k3 3) '(k3 0))

그리고 반환

'(k1 1 k2 2 k3 0))

이것은 Clojure의 병합과 같이 가장 올바른 스타일입니다.

  1. "그들은 목록이므로 추가 만 하시겠습니까?"

아니요, 속성 목록 의미를 append유지하지 않습니다 . 이:

(append '(k1 1 k2 2) '(k2 0))

이것을 돌려줍니다 :

(k1 1 k2 2 k2 0)

append는`C 소스 코드 '에 내장 된 함수입니다.

(시퀀스 추가 및 휴식)

모든 인수를 연결하고 결과를 목록으로 만듭니다. 결과는 해당 요소가 모든 인수의 요소 인 목록입니다. 각 인수는 목록, 벡터 또는 문자열 일 수 있습니다. 마지막 인수는 복사되지 않고 새 목록의 꼬리로 사용됩니다.

  1. "그리고 당신의 예제는 병합과 같은 것을 보여주지 않습니다 – 심지어 두 개의 속성리스트도 보여주지 않습니다."

그렇습니다. 단계별로 병합을 수행합니다. Elisp의 문서화 된 속성 목록 함수를 사용하여 병합하는 것이 얼마나 장황한 지 보여줍니다.

(setq pl nil)
(setq pl (plist-put pl 'key-1 'value-1))
(setq pl (plist-put pl 'key-2 'value-2))

다음에서 결과 출력 값을 표시하십시오 pl.

(key-1 value-1 key-2 value-2)

다시 말하지만,이 문제를 해결하기 위해 함수를 작성할 수는 있지만, 먼저 그러한 함수가 일반적인 용도로 존재하는지 알아 내고 싶었습니다.

마지막으로, 불명확하다고 판단하여 질문을 하향 조정 한 경우, 명확히하기 위해 몇 가지 노력을 기울 였다는 점을 다시 생각해보십시오. 이것은 연구의 부족이 아닙니다. "목록"에있는 Elisp 문서는 질문에 대답하지 않습니다.


2
그들은 목록입니다 append.
abo-abo

2
원하는 동작을 정확하게 지정하십시오. 두 목록을 "병합"하는 방법에는 여러 가지가 있습니다. 그리고 귀하의 예는 병합과 같은 것을 보여주지 않습니다-심지어 두 개의 속성 목록을 보여 주지도 않습니다. 지금까지이 질문은 불분명 한 것으로 종결되어야합니다. FWIW, plist의 앞쪽에 더 가까운 쌍은 앞쪽에서 더 먼 같은 키를 가진 쌍을 숨 깁니다. 따라서 병합은 한 plist의 요소를 다른 plist의 요소 앞에 놓는 것을 의미 할 수 있습니다.
Drew

1
@ abo-abo : Emacs Lisp Manual속성 이름이 고유해야 한다고 명시되어 있습니다 .
Constantine

3
가장 오른쪽에있는 목록을 확인하려면 당신은 당신이에 전달되는 목록의 순서 반대로해야 이길 append: (let ((args '((:a 1 :b 1) (:b 2) (:a 3)))) (apply #'append (reverse args))) => (:a 3 :b 2 :a 1 :b 1)같은 인 (:a 3 :b 2 :a 1)당신이 단지 PLIST에 액세스 할 수 PLIST 기능을 사용할만큼을.
tarsius

1
@Constantine는 : 오른쪽도 있지만 plist-get이나 plist-member여러 개의 동일한 키가있는 경우 관심을 보인다. 다음과 같은 점에서 목록과 유사하게 작동하는 것 같습니다 (plist-get '(:a "a" :b "b" :a "c") :a) ==> "a". 한편, (plist-put '(:a "a" :b "b" :a "c") :a "d")첫 번째 :a키 의 값을 대체 하지만 두 번째 키 는 대체 하지 않습니다.
Dan

답변:


8

Emacs에 포함 된 조직 모드에는 plist 병합 기능이 있습니다.

(defun org-combine-plists (&rest plists)
  "Create a single property list from all plists in PLISTS.
The process starts by copying the first list, and then setting properties
from the other lists.  Settings in the last list are the most significant
ones and overrule settings in the other lists."
  (let ((rtn (copy-sequence (pop plists)))
        p v ls)
    (while plists
      (setq ls (pop plists))
      (while ls
        (setq p (pop ls) v (pop ls))
        (setq rtn (plist-put rtn p v))))
    rtn))

그것을 사용하려면 (require 'org)먼저 파일을로드해야합니다. 불행히도 파일은 900 + KB의 매우 큰 파일이므로 실제로 유틸리티 라이브러리로 사용할 수는 없습니다. 표준 plist 패키지와 같은 것이 좋습니다.

나는 최근에 아주 작은 것을 시작했고 alists와 plists가 같은 인수 방식으로 취급되지 않는다는 것을 깨달았습니다-예를 들어 (plist-get LIST KEY) vs (assoc KEY LIST). 불행히도 최적화의 유물이어야합니다 (또는?) .

그러나 Emacs에는 멋진 plist 라이브러리가 필요합니다. 검색에서 다른 라이브러리를 발견하지 못했지만 어딘가에 다른 라이브러리가있을 수 있습니다. 그렇지 않으면 시작하여 Elpa / Melpa에 배치해야합니다. .

동일한 인터페이스를 가진 목록 라이브러리도 있으면 좋을 것입니다.


6

매뉴얼을 읽고 목록을 탐색 C-u C-h a plist RET해도 두 속성 목록을 병합하는 기능은 켜지지 않습니다. Common Lisp 확장은 속성 목록에 작용하는 기능을 제공하지 않으며 ( getf/ setf/…) 만 지원합니다. 따라서 타사 라이브러리에 의존하거나 자신의 롤을 사용해야합니다.

자신을 굴리는 것은 그리 어렵지 않습니다. 이 구현은 충돌시 마지막 값을 사용합니다.

(defun plist-merge (&rest plists)
  (if plists
      (let ((result (copy-sequence (car plists))))
        (while (setq plists (cdr plists))
          (let ((plist (car plists)))
            (while plist
              (setq result (plist-put result (car plist) (car (cdr plist)))
                    plist (cdr (cdr plist))))))
        result)
    nil))

(plist-merge '(:x 2 :y 3)
             '(     :y 0 :z 7))
=>            (:x 2 :y 0 :z 7)

좋은. 왜 당신 copy-sequence은 첫 번째 주술사이지만 다른 사람은 아니십니까? 또한, 당신은 중첩을 가진 비트를 정리할 수 있습니다 cadrcddr.
fommil

실제로 org-combine-plists(아래)는 정리 된 버전입니다. 나는 왜 그들이 차인지 이해하지 못한다 copy-sequence.
fommil

0

나는 이것이 이미 답변되었다는 것을 알고 있지만, 누군가 관심이 org있다면 구현을하고 코드 골프를 조금 연주했다.

(defun plist-merge (&rest plists)
  "Create a single property list from all PLISTS.
Inspired by `org-combine-plists'."
  (let ((rtn (pop plists)))
    (dolist (plist plists rtn)
      (setq rtn (plist-put rtn
                           (pop plist)
                           (pop plist))))))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.