Bir özellik bir özellik listesinde eşlensin mi?


17

S: Bir işlevi bir özellik listesinde eşlemenin deyimsel yolu nedir?

Çeşitli eşleme işlevleri ( mapcarve ailesi), bir işlevi liste gibi bir dizi üzerinde eşler. Bir özellik listesi ile uğraşırken , yani listede yer alan özelliklerin her birini eşleştirmeye çalışırken (birincisinden başlayarak diğer tüm öğeler olur) bu işlevleri nasıl kullanır ? Bana öyle geliyor ki, haritalama fonksiyonu listeye tek tek elemanlar yerine elemanlar halinde erişmesi gerekecek.

Oyuncak örneği olarak, bir özellik listesi nasıl alınır ve tüm özellik değerleri toplanır? Bir ilişkilendirme listesi olsaydı, oldukça basit olurdu:

(mapcar #'cadr '((:prop1 a) (:prop2 b) (:prop3 c))) ;=> (a b c)

Bu bir döngü ile yapılabilir eminim, ama biraz zahmetli görünüyor ve bunu yapmak için daha deyimsel bir yol olup olmadığını merak ediyorum.


Lütfen yalnızca özellik değerlerini eşleştirmek isteyip istemediğinizi (kulağa benzediği ve mapcaralist örneğinizin yaptığı şey) veya özellik sembolü ve özellik değeri çiftleri üzerinden eşleştirmek istediğinizi açıklayın . İkincisi daha genel (daha genel olarak yararlı), sanırım.
Drew

@ Çekildi: Genel durumla daha çok ilgileniyorum; örnek aklıma gelen en basit örnekti. Mülk / değer çifti üzerinden nasıl harita yapılacağını bilmek istiyorum . Cevap "bir döngü" ise, öyle olsun, ama daha zarif bir çözüm olup olmadığını merak ediyorum.
Dan

Örneğinizde bulunanlar bir özellik listesi değildir. Özellik listeleri çift sayıda öğeye, tek öğeler özellik adları, hatta öğeler özellik değerleridir. Muhtemelen bir ağaç (listelerin listesi) olarak adlandırılırdı.
wvxvw

Yanıtlar:


8

Muhtemelen çeşitli loopve yineleme cevapları alacaksınız . AFAIK, bunu yapmanın deyimsel bir yolu yok. Ben sadece özellik değerleri (özellikleri ile ilişkilendirerek değil) biriktirmek için çok yaygın olduğunu sanmıyorum.

İşte bunu yapmanın basit bir yolu:

(defun prop-values (plist)
  "..."
  (let ((pl    (cdr plist))
        (vals  ()))
    (while pl
      (push (car pl) vals)
      (setq pl  (cddr pl)))
    (nreverse vals)))

İkili bir işlevi bir plist üzerinden eşlemek istediğiniz daha genel durum için:

(defun map-plist (fn plist)
  "..."
  (let ((pl    plist)
        (vals  ()))
    (while pl
      (push (funcall fn (car pl) (cadr pl)) vals)
      (setq pl (cddr pl)))
    (nreverse vals)))

(setq foo '(a 1 b 2 c 3 d 4 e 5))

(map-plist #'cons foo) ; => ((a . 1) (b . 2) (c . 3) (d . 4) (e . 5))

13

Bu muhtemelen bir duruma bağlı olacaktır. Genel olarak, bir dizi adla bir dizi değeri bağlamam gerekirse, bir karma tablo kullanırdım, ancak bir özellik listesi kullanmam gerekirse, kullanardım cl-loop. Aşağıda bazı örnekler verilmiştir:

(cl-loop for (key value) on '(:prop1 a :prop2 b :prop3 c) by 'cddr
         collect value)
;;; (a b c)

Ve örneğinizde gösterdiğiniz bir veri yapınız varsa:

(cl-loop for (key value) in '((:prop1 a) (:prop2 b) (:prop3 c))
         collect value)
;;; (a b c)

5

Benim için cevap, plist'i eşdeğer bir veri yapısı olan bir aliste dönüştürmek, sadece yarısı kadar derin ve manipüle edilmesi daha kolay.


3
Bu bir cevap (ve iyi bir tavsiye), ama daha çok bir yorum.
Drew

4

Mevcut Git HEAD'den Emacs 25 olacak Emacs ile aşağıdakileri yapabilirsiniz, yani plist'i yeni seq-partitionişlevle kolayca bir alist haline getirebilir ve daha sonra standart kullanarak alist girişlerini işleyebilirsiniz mapcar.

(let* ((my-plist (list :a 1 :b 2 :c 3 :more (list 4 5 6)))
       (my-alist (seq-partition my-plist 2))
       (my-reverse-alist (mapcar (lambda (entry)
                                   (let ((prop (car entry))
                                         (val  (cadr entry)))
                                     (list val prop)))
                                 my-alist)))
  (message "my-plist: %s\nmy-alist: %s\nmy-reverse-alist: %s"
           my-plist my-alist my-reverse-alist))
;; my-plist: (:a 1 :b 2 :c 3 :more (4 5 6))
;; my-alist: ((:a 1) (:b 2) (:c 3) (:more (4 5 6)))
;; my-reverse-alist: ((1 :a) (2 :b) (3 :c) ((4 5 6) :more))

seq-partitionKullanarak belgelere bir göz atın C-h f seq-partition RET.


1

Bir fikir kullanmaktır -map-indexedgelen dashve sadece listenin tek değerlere dönüşümü uygulanır:

(-non-nil (-map-indexed (lambda (index item) (when (oddp index) item))
  '(a x b y c z))) ; => (x y z)
(-non-nil (--map-indexed (when (oddp it-index) it) '(a x b y c z))) ; => (x y z)

Başka bir fikir sadece kullanan karma-tabloya bir plist dönüştürmektir ht<-plistden ht:

(ht-values (ht<-plist '(a x b y c z) 'equal)) ; (z y x)

Karma tablonun öğelerin sırasını korumadığına dikkat edin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.