سؤال

أحاول تعلم LISP، باستخدام لهجة EMACS ولدي سؤال. دعنا نقول أن القائمة لديها بعض الأعضاء، والتي يقيم المسند false. كيف يمكنني إنشاء قائمة جديدة دون هؤلاء الأعضاء؟ شيء مثل { A in L: p(A) is true }. وبعد في بيثون هناك وظيفة مرشح، هل هناك شيء ما يعادل في LISP؟ إذا لم يكن كذلك، كيف أفعل ذلك؟

شكرا

هل كانت مفيدة؟

المحلول

هذه الوظائف في حزمة CL، سوف تحتاج إلى (require 'cl) لاستخدامها:

(remove-if-not #'evenp '(1 2 3 4 5))

سيؤدي ذلك إلى إرجاع قائمة جديدة مع جميع الأرقام حتى من الحجة.

ابحث أيضا delete-if-not, ، الذي يفعل نفسه، ولكن يعدل قائمة الحجة الخاصة به.

نصائح أخرى

إذا كنت تلاعب قوائم بكثافة في التعليمات البرمجية الخاصة بك، يرجى استخدام dash.el مكتبة البرمجة الوظيفية الحديثة، بدلا من كتابة رمز الغزل وإعادة اختراع العجلة. لديها كل وظيفة للعمل مع القوائم والأشجار وتطبيق الوظيفة والتحكم في التدفق يمكنك تخيلها. للحفاظ على جميع العناصر التي تتطابق مع المسند وإزالة الآخرين تحتاج -filter:

(-filter (lambda (x) (> x 2)) '(1 2 3 4 5)) ; (3 4 5)

وظائف أخرى ذات الاهتمام تشمل -remove, -take-while, -drop-while:

(-remove (lambda (x) (> x 2)) '(1 2 3 4 5)) ; (1 2)    
(-take-while (lambda (x) (< x 3)) '(1 2 3 2 1)) ; (1 2)
(-drop-while (lambda (x) (< x 3)) '(1 2 3 2 1)) ; (3 2 1)

ما هو رائع dash.el هو أنه يدعم وحدات ماكرو الاستعكارية. وبعد وحدات ماكرو الاستعكارية تتصرف مثل الوظائف، لكنها تسمح بجميع بناء الجملة الخاص بإجراء مزيد من التعليمات البرمجية. بدلا من توفير وظيفة مجهولة كحجة، مجرد كتابة S التعبير واستخدام it بدلا من متغير محلي، مثل x في الأمثلة السابقة. ما يقابل وحدات وحدات الماكرو المراسلة مع 2 شرطات بدلا من واحد:

(--filter (> it 2) '(1 2 3 4 5)) ; (3 4 5)
(--remove (> it 2) '(1 2 3 4 5)) ; (1 2)
(--take-while (< it 3) '(1 2 3 2 1)) ; (1 2)
(--drop-while (< it 3) '(1 2 3 2 1)) ; (3 2 1)

كنت أبحث عن نفس الليلة الماضية واتبرت عبر elisp كوكب على emacswiki.. القسم في القوائم / التسلسلات يحتوي على تصفية Teqniques وإظهار كيف يمكن القيام بذلك mapcar و delq. وبعد اضطررت إلى تعديل الرمز لاستخدامه لأغراض بلدي ولكن هنا هو الأصلي:

;; Emacs Lisp doesn’t come with a ‘filter’ function to keep elements that satisfy 
;; a conditional and excise the elements that do not satisfy it. One can use ‘mapcar’ 
;; to iterate over a list with a conditional, and then use ‘delq’ to remove the ‘nil’  
;; values.

   (defun my-filter (condp lst)
     (delq nil
           (mapcar (lambda (x) (and (funcall condp x) x)) lst)))

;; Therefore

  (my-filter 'identity my-list)

;; is equivalent to

  (delq nil my-list)

;; For example:

  (let ((num-list '(1 'a 2 "nil" 3 nil 4)))
    (my-filter 'numberp num-list))   ==> (1 2 3 4)

;; Actually the package cl-seq contains the functions remove-if and remove-if-not. 
;; The latter can be used instead of my-filter.

Emacs الآن يأتي مع المكتبة seq.el, ، استعمال seq-remove.

seq-remove (pred sequence) 
"Return a list of all the elements for which (PRED element) is nil in SEQUENCE."

مع LISP المشترك، يمكنك تنفيذ الوظيفة كما يلي:

(defun my-filter  (f args)
    (cond ((null args) nil)
        ((if (funcall f (car args))
            (cons (car args) (my-filter  f (cdr args)))
            (my-filter  f (cdr args))))))

(print 
      (my-filter #'evenp '(1 2 3 4 5)))

هناك طن من الطرق لتصفية أو تحديد الاشياء من قائمة باستخدام المدمجات المدمجة التي هي أسرع بكثير من الحلقات. إزالة المدمج - إذا كان يمكن استخدامها بهذه الطريقة. على سبيل المثال، لنفترض أنني أريد إسقاط العناصر 3 إلى 10 في قائمة MyList. تنفيذ التعليمات البرمجية التالية كمثال:

(let ((MyList (number-sequence 0 9))
      (Index -1)
      )
  (remove-if #'(lambda (Elt)
                  (setq Index (1+ Index))
                  (and (>= Index 3) (<= Index 5))
                  )
              MyList
           )
 )

سوف تحصل على '(0 1 2 6 7 8 9).

لنفترض أنك تريد الاحتفاظ بالعناصر فقط بين 3 و 5. أنت تقلب في الأساس الحالة التي كتبتها أعلاه في المسند.

(let ((MyList (number-sequence 0 9))
      (Index -1)
      )
  (remove-if #'(lambda (Elt)
                   (setq Index (1+ Index))
                   (or (< Index 3) (> Index 5))
                  )
              MyList
           )
 )

سوف تحصل على '(3 4 5)

يمكنك استخدام كل ما تحتاجه للمسند الذي يجب أن توفره لإزالة - إذا. الحد الوحيد هو خيالك حول ما يجب استخدامه. يمكنك استخدام وظائف تصفية التسلسل، لكنك لا تحتاج إليها.

بدلا من ذلك، يمكنك أيضا استخدام MapCar أو Mapcar * للحلقة على قائمة باستخدام بعض الوظائف التي تحول دون إدخالات محددة إلى NIL والاستخدام (إزالة - إذا كان Nil ...) لإسقاط NILS.

من المستغرب أنه لا يوجد نسخة مدمجة من مرشح دون cl او او seq وهو جديد جدا).

تنفيذ filter المذكورة هنا (التي تراها في كتاب الطبخ Elisp وأماكن أخرى) غير صحيحة. ويستخدم ذلك nil كعلامة للعناصر المراد إزالتها، مما يعني إذا كان لديك nilفي قائمتك لتبدأ، سيتم إزالتها حتى لو كانوا يرضون المسند.

لتصحيح هذا التنفيذ، nil يجب استبدال علامات استبدال برمز دائم (أي جينميم).

(defun my-filter (pred list)
  (let ((DELMARKER (make-symbol "DEL")))
    (delq
      DELMARKER
      (mapcar (lambda (x) (if (funcall pred x) x DELMARKER))
              list))))
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top