Lisp/Intersection of Lists












1















Hello i am trying to create a function in common-lisp that takes two lists, and output their intersections, assuming there is no repetition in each list without using intersection function. It seems that it is not working. Can anyone help?



(defun isect (lst_1 lst_2)
(setq newlist nil)
(dolist (x lst_1 newlist)
(dolist (y lst_2)
(if (equal x y) (setf newlist (append newlist x)))
)
)
)









share|improve this question




















  • 2





    "It seems that it is not working." Please add error messages, if you have any

    – coredump
    Nov 8 '18 at 15:10








  • 1





    Your function unnecessarily refers to a free variable. The variable newlist has no binding in the function; it is global. Lisp isn't Python; assigning to a symbol doesn't create a local variable. It refers to an existing variable, and if one hasn't been defined, then it refers to the symbol's global value cell.

    – Kaz
    Nov 8 '18 at 21:34






  • 1





    ^ ... I.e. your (setq newlist nil) is doing the same thing as (setf (symbol-value 'newlist) nil).

    – Kaz
    Nov 8 '18 at 21:35






  • 1





    ^ and this is "bad" because multiple unrelated functions in the Lisp image could use newlist in the same way, leading to bugs. Another function that uses newlist might malfunction due to the surprise that a call to isect overwrote the variable. Deliberate, purposeful, organized global variables are already fairly bad in software; accidental global variables are worse.

    – Kaz
    Nov 8 '18 at 21:38
















1















Hello i am trying to create a function in common-lisp that takes two lists, and output their intersections, assuming there is no repetition in each list without using intersection function. It seems that it is not working. Can anyone help?



(defun isect (lst_1 lst_2)
(setq newlist nil)
(dolist (x lst_1 newlist)
(dolist (y lst_2)
(if (equal x y) (setf newlist (append newlist x)))
)
)
)









share|improve this question




















  • 2





    "It seems that it is not working." Please add error messages, if you have any

    – coredump
    Nov 8 '18 at 15:10








  • 1





    Your function unnecessarily refers to a free variable. The variable newlist has no binding in the function; it is global. Lisp isn't Python; assigning to a symbol doesn't create a local variable. It refers to an existing variable, and if one hasn't been defined, then it refers to the symbol's global value cell.

    – Kaz
    Nov 8 '18 at 21:34






  • 1





    ^ ... I.e. your (setq newlist nil) is doing the same thing as (setf (symbol-value 'newlist) nil).

    – Kaz
    Nov 8 '18 at 21:35






  • 1





    ^ and this is "bad" because multiple unrelated functions in the Lisp image could use newlist in the same way, leading to bugs. Another function that uses newlist might malfunction due to the surprise that a call to isect overwrote the variable. Deliberate, purposeful, organized global variables are already fairly bad in software; accidental global variables are worse.

    – Kaz
    Nov 8 '18 at 21:38














1












1








1








Hello i am trying to create a function in common-lisp that takes two lists, and output their intersections, assuming there is no repetition in each list without using intersection function. It seems that it is not working. Can anyone help?



(defun isect (lst_1 lst_2)
(setq newlist nil)
(dolist (x lst_1 newlist)
(dolist (y lst_2)
(if (equal x y) (setf newlist (append newlist x)))
)
)
)









share|improve this question
















Hello i am trying to create a function in common-lisp that takes two lists, and output their intersections, assuming there is no repetition in each list without using intersection function. It seems that it is not working. Can anyone help?



(defun isect (lst_1 lst_2)
(setq newlist nil)
(dolist (x lst_1 newlist)
(dolist (y lst_2)
(if (equal x y) (setf newlist (append newlist x)))
)
)
)






lisp common-lisp set-intersection






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 8 '18 at 14:29







Alper Oguzkan

















asked Nov 8 '18 at 13:59









Alper OguzkanAlper Oguzkan

133




133








  • 2





    "It seems that it is not working." Please add error messages, if you have any

    – coredump
    Nov 8 '18 at 15:10








  • 1





    Your function unnecessarily refers to a free variable. The variable newlist has no binding in the function; it is global. Lisp isn't Python; assigning to a symbol doesn't create a local variable. It refers to an existing variable, and if one hasn't been defined, then it refers to the symbol's global value cell.

    – Kaz
    Nov 8 '18 at 21:34






  • 1





    ^ ... I.e. your (setq newlist nil) is doing the same thing as (setf (symbol-value 'newlist) nil).

    – Kaz
    Nov 8 '18 at 21:35






  • 1





    ^ and this is "bad" because multiple unrelated functions in the Lisp image could use newlist in the same way, leading to bugs. Another function that uses newlist might malfunction due to the surprise that a call to isect overwrote the variable. Deliberate, purposeful, organized global variables are already fairly bad in software; accidental global variables are worse.

    – Kaz
    Nov 8 '18 at 21:38














  • 2





    "It seems that it is not working." Please add error messages, if you have any

    – coredump
    Nov 8 '18 at 15:10








  • 1





    Your function unnecessarily refers to a free variable. The variable newlist has no binding in the function; it is global. Lisp isn't Python; assigning to a symbol doesn't create a local variable. It refers to an existing variable, and if one hasn't been defined, then it refers to the symbol's global value cell.

    – Kaz
    Nov 8 '18 at 21:34






  • 1





    ^ ... I.e. your (setq newlist nil) is doing the same thing as (setf (symbol-value 'newlist) nil).

    – Kaz
    Nov 8 '18 at 21:35






  • 1





    ^ and this is "bad" because multiple unrelated functions in the Lisp image could use newlist in the same way, leading to bugs. Another function that uses newlist might malfunction due to the surprise that a call to isect overwrote the variable. Deliberate, purposeful, organized global variables are already fairly bad in software; accidental global variables are worse.

    – Kaz
    Nov 8 '18 at 21:38








2




2





"It seems that it is not working." Please add error messages, if you have any

– coredump
Nov 8 '18 at 15:10







"It seems that it is not working." Please add error messages, if you have any

– coredump
Nov 8 '18 at 15:10






1




1





Your function unnecessarily refers to a free variable. The variable newlist has no binding in the function; it is global. Lisp isn't Python; assigning to a symbol doesn't create a local variable. It refers to an existing variable, and if one hasn't been defined, then it refers to the symbol's global value cell.

– Kaz
Nov 8 '18 at 21:34





Your function unnecessarily refers to a free variable. The variable newlist has no binding in the function; it is global. Lisp isn't Python; assigning to a symbol doesn't create a local variable. It refers to an existing variable, and if one hasn't been defined, then it refers to the symbol's global value cell.

– Kaz
Nov 8 '18 at 21:34




1




1





^ ... I.e. your (setq newlist nil) is doing the same thing as (setf (symbol-value 'newlist) nil).

– Kaz
Nov 8 '18 at 21:35





^ ... I.e. your (setq newlist nil) is doing the same thing as (setf (symbol-value 'newlist) nil).

– Kaz
Nov 8 '18 at 21:35




1




1





^ and this is "bad" because multiple unrelated functions in the Lisp image could use newlist in the same way, leading to bugs. Another function that uses newlist might malfunction due to the surprise that a call to isect overwrote the variable. Deliberate, purposeful, organized global variables are already fairly bad in software; accidental global variables are worse.

– Kaz
Nov 8 '18 at 21:38





^ and this is "bad" because multiple unrelated functions in the Lisp image could use newlist in the same way, leading to bugs. Another function that uses newlist might malfunction due to the surprise that a call to isect overwrote the variable. Deliberate, purposeful, organized global variables are already fairly bad in software; accidental global variables are worse.

– Kaz
Nov 8 '18 at 21:38












4 Answers
4






active

oldest

votes


















1














I assume isect with both arguments being the same list should return an equal list and not one that is flattened. In that case (append newlist x) is not adding an element to the end of a list. Here is my suggestion:



(defun intersect (lst-a lst-b &aux result)
(dolist (a lst-a (nreverse result))
(dolist (b lst-b)
(when (equal a b)
(push a result)))))


This is O(n^2) while you can do it in O(n) using a hash table.






share|improve this answer
























  • I am newbie to Lisp, yeah i realized that append does not change the original list, i have re-defined my function using push macro. Thanks further.

    – Alper Oguzkan
    Nov 13 '18 at 14:21





















0














If you can ensure that the lists are sorted (ascending) you could do something like



(defun isect (l1 l2 acc)
(let ((f1 (car l1))
(f2 (car l2))
(r1 (cdr l1))
(r2 (cdr l2)))
(cond ((or (null l1) (null l2)) acc)
((= f1 f2) (isect r1 r2 (cons f1 acc)))
((< f1 f2) (isect r1 l2 acc))
((> f1 f2) (isect l1 r2 acc)))))


Note though, that the result is in reversed order. Also, the example assumes that the
elements are numbers. If you wanted to generalize, you could pass an ordering as an optional argument to make it work with arbitrary elements.



NB: A solution using loop would likely be faster but I could not think of how to partially "advance" the lists when the cars are different.






share|improve this answer

































    0














    A built-in way (that won't work for homeworks ;) ) is to use intersection: https://lispcookbook.github.io/cl-cookbook/data-structures.html#intersection-of-lists



    What elements are both in list-a and list-b ?



    (defparameter list-a '(0 1 2 3))
    (defparameter list-b '(0 2 4))
    (intersection list-a list-b)
    ;; => (2 0)





    share|improve this answer































      0














      ;; the key function for simple lists
      (defun id (x) x)

      ;; the intersect function for two lists
      ;; with sorting included:
      ;; you need an equality-test:
      ;; default is #'eql (for simple numbers or symbols this is sufficient)
      ;; - for numbers only #'=
      ;; - for characters only #'char=
      ;; - for strings only #'string=
      ;; - for lists #'equal
      ;; - for nearly everything #'equalp (case insensitive for char/strings!)
      ;; then you need also a sorting tester:
      ;; - increasing number: #'<
      ;; - decreasing number: #'>
      ;; - increasing char: #'char<
      ;; - decreasing char: #'char>
      ;; - increasing strings: #'string<
      ;; - decreasing strings: #'string>
      ;; - other cases I haven't think of - does somebody have an idea?
      ;; (one could sort by length of element etc.)
      ;; so sort-test should be a diadic function (function taking 2 arguments to compare)
      ;; then you also need an accessor function
      ;; so, how withing each element the to-be-sorted element should be accessed
      ;; for this, I prepared the `id` - identity - function because this is the
      ;; sort-key when simple comparison of the elements of the two lists
      ;; should be compared - and this function is also used for testing
      ;; for equality in the inner `.isect` function.
      (defun isect (lst-1 lst-2 &key (equality-test #'eql) (sort-test #'<) (sort-key #'id))
      (let ((lst-1-sorted (stable-sort lst-1 sort-test :key sort-key))
      (lst-2-sorted (stable-sort lst-2 sort-test :key sort-key)))
      (labels ((.isect (l1 l2 acc)
      (cond ((or (null l1) (null l2)) (nreverse acc))
      (t (let ((l1-element (funcall sort-key (car l1)))
      (l2-element (funcall sort-key (car l2))))
      (cond ((funcall sort-test l1-element l2-element)
      (.isect (cdr l1) l2 acc))
      ((funcall equality-test l1-element l2-element)
      (.isect (cdr l1) (cdr l2) (cons (car l1) acc)))
      (t (.isect l1 (cdr l2) acc))))))))
      (.isect lst-1-sorted lst-2-sorted '()))))


      Simple tests:



      (isect '(0 1 2 3 4 5 6) '(9 0 3 5 12 24 8 6))
      ;; => (0 3 5 6)

      (isect '(#a #c #h #t #e #r #b #a #h #n)
      '(#a #m #s #e #l #s #t #a #r)
      :equality-test #'char=
      :sort-test #'char<
      :key #'id)
      ;; => (#a #a #e #r #t)

      (isect '("this" "is" "just" "a" "boring" "test")
      '("this" "boring" "strings" "are" "to" "be" "intersected")
      :equality-test #'string=
      :sort-test #'string<
      :key #'id)
      ;; => ("boring" "this")





      share|improve this answer























        Your Answer






        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "1"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53209247%2flisp-intersection-of-lists%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        4 Answers
        4






        active

        oldest

        votes








        4 Answers
        4






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        1














        I assume isect with both arguments being the same list should return an equal list and not one that is flattened. In that case (append newlist x) is not adding an element to the end of a list. Here is my suggestion:



        (defun intersect (lst-a lst-b &aux result)
        (dolist (a lst-a (nreverse result))
        (dolist (b lst-b)
        (when (equal a b)
        (push a result)))))


        This is O(n^2) while you can do it in O(n) using a hash table.






        share|improve this answer
























        • I am newbie to Lisp, yeah i realized that append does not change the original list, i have re-defined my function using push macro. Thanks further.

          – Alper Oguzkan
          Nov 13 '18 at 14:21


















        1














        I assume isect with both arguments being the same list should return an equal list and not one that is flattened. In that case (append newlist x) is not adding an element to the end of a list. Here is my suggestion:



        (defun intersect (lst-a lst-b &aux result)
        (dolist (a lst-a (nreverse result))
        (dolist (b lst-b)
        (when (equal a b)
        (push a result)))))


        This is O(n^2) while you can do it in O(n) using a hash table.






        share|improve this answer
























        • I am newbie to Lisp, yeah i realized that append does not change the original list, i have re-defined my function using push macro. Thanks further.

          – Alper Oguzkan
          Nov 13 '18 at 14:21
















        1












        1








        1







        I assume isect with both arguments being the same list should return an equal list and not one that is flattened. In that case (append newlist x) is not adding an element to the end of a list. Here is my suggestion:



        (defun intersect (lst-a lst-b &aux result)
        (dolist (a lst-a (nreverse result))
        (dolist (b lst-b)
        (when (equal a b)
        (push a result)))))


        This is O(n^2) while you can do it in O(n) using a hash table.






        share|improve this answer













        I assume isect with both arguments being the same list should return an equal list and not one that is flattened. In that case (append newlist x) is not adding an element to the end of a list. Here is my suggestion:



        (defun intersect (lst-a lst-b &aux result)
        (dolist (a lst-a (nreverse result))
        (dolist (b lst-b)
        (when (equal a b)
        (push a result)))))


        This is O(n^2) while you can do it in O(n) using a hash table.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 8 '18 at 15:35









        SylwesterSylwester

        34.4k22955




        34.4k22955













        • I am newbie to Lisp, yeah i realized that append does not change the original list, i have re-defined my function using push macro. Thanks further.

          – Alper Oguzkan
          Nov 13 '18 at 14:21





















        • I am newbie to Lisp, yeah i realized that append does not change the original list, i have re-defined my function using push macro. Thanks further.

          – Alper Oguzkan
          Nov 13 '18 at 14:21



















        I am newbie to Lisp, yeah i realized that append does not change the original list, i have re-defined my function using push macro. Thanks further.

        – Alper Oguzkan
        Nov 13 '18 at 14:21







        I am newbie to Lisp, yeah i realized that append does not change the original list, i have re-defined my function using push macro. Thanks further.

        – Alper Oguzkan
        Nov 13 '18 at 14:21















        0














        If you can ensure that the lists are sorted (ascending) you could do something like



        (defun isect (l1 l2 acc)
        (let ((f1 (car l1))
        (f2 (car l2))
        (r1 (cdr l1))
        (r2 (cdr l2)))
        (cond ((or (null l1) (null l2)) acc)
        ((= f1 f2) (isect r1 r2 (cons f1 acc)))
        ((< f1 f2) (isect r1 l2 acc))
        ((> f1 f2) (isect l1 r2 acc)))))


        Note though, that the result is in reversed order. Also, the example assumes that the
        elements are numbers. If you wanted to generalize, you could pass an ordering as an optional argument to make it work with arbitrary elements.



        NB: A solution using loop would likely be faster but I could not think of how to partially "advance" the lists when the cars are different.






        share|improve this answer






























          0














          If you can ensure that the lists are sorted (ascending) you could do something like



          (defun isect (l1 l2 acc)
          (let ((f1 (car l1))
          (f2 (car l2))
          (r1 (cdr l1))
          (r2 (cdr l2)))
          (cond ((or (null l1) (null l2)) acc)
          ((= f1 f2) (isect r1 r2 (cons f1 acc)))
          ((< f1 f2) (isect r1 l2 acc))
          ((> f1 f2) (isect l1 r2 acc)))))


          Note though, that the result is in reversed order. Also, the example assumes that the
          elements are numbers. If you wanted to generalize, you could pass an ordering as an optional argument to make it work with arbitrary elements.



          NB: A solution using loop would likely be faster but I could not think of how to partially "advance" the lists when the cars are different.






          share|improve this answer




























            0












            0








            0







            If you can ensure that the lists are sorted (ascending) you could do something like



            (defun isect (l1 l2 acc)
            (let ((f1 (car l1))
            (f2 (car l2))
            (r1 (cdr l1))
            (r2 (cdr l2)))
            (cond ((or (null l1) (null l2)) acc)
            ((= f1 f2) (isect r1 r2 (cons f1 acc)))
            ((< f1 f2) (isect r1 l2 acc))
            ((> f1 f2) (isect l1 r2 acc)))))


            Note though, that the result is in reversed order. Also, the example assumes that the
            elements are numbers. If you wanted to generalize, you could pass an ordering as an optional argument to make it work with arbitrary elements.



            NB: A solution using loop would likely be faster but I could not think of how to partially "advance" the lists when the cars are different.






            share|improve this answer















            If you can ensure that the lists are sorted (ascending) you could do something like



            (defun isect (l1 l2 acc)
            (let ((f1 (car l1))
            (f2 (car l2))
            (r1 (cdr l1))
            (r2 (cdr l2)))
            (cond ((or (null l1) (null l2)) acc)
            ((= f1 f2) (isect r1 r2 (cons f1 acc)))
            ((< f1 f2) (isect r1 l2 acc))
            ((> f1 f2) (isect l1 r2 acc)))))


            Note though, that the result is in reversed order. Also, the example assumes that the
            elements are numbers. If you wanted to generalize, you could pass an ordering as an optional argument to make it work with arbitrary elements.



            NB: A solution using loop would likely be faster but I could not think of how to partially "advance" the lists when the cars are different.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 13 '18 at 21:05

























            answered Nov 9 '18 at 16:35









            AroobAroob

            467




            467























                0














                A built-in way (that won't work for homeworks ;) ) is to use intersection: https://lispcookbook.github.io/cl-cookbook/data-structures.html#intersection-of-lists



                What elements are both in list-a and list-b ?



                (defparameter list-a '(0 1 2 3))
                (defparameter list-b '(0 2 4))
                (intersection list-a list-b)
                ;; => (2 0)





                share|improve this answer




























                  0














                  A built-in way (that won't work for homeworks ;) ) is to use intersection: https://lispcookbook.github.io/cl-cookbook/data-structures.html#intersection-of-lists



                  What elements are both in list-a and list-b ?



                  (defparameter list-a '(0 1 2 3))
                  (defparameter list-b '(0 2 4))
                  (intersection list-a list-b)
                  ;; => (2 0)





                  share|improve this answer


























                    0












                    0








                    0







                    A built-in way (that won't work for homeworks ;) ) is to use intersection: https://lispcookbook.github.io/cl-cookbook/data-structures.html#intersection-of-lists



                    What elements are both in list-a and list-b ?



                    (defparameter list-a '(0 1 2 3))
                    (defparameter list-b '(0 2 4))
                    (intersection list-a list-b)
                    ;; => (2 0)





                    share|improve this answer













                    A built-in way (that won't work for homeworks ;) ) is to use intersection: https://lispcookbook.github.io/cl-cookbook/data-structures.html#intersection-of-lists



                    What elements are both in list-a and list-b ?



                    (defparameter list-a '(0 1 2 3))
                    (defparameter list-b '(0 2 4))
                    (intersection list-a list-b)
                    ;; => (2 0)






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Nov 14 '18 at 11:59









                    EhvinceEhvince

                    8,57042652




                    8,57042652























                        0














                        ;; the key function for simple lists
                        (defun id (x) x)

                        ;; the intersect function for two lists
                        ;; with sorting included:
                        ;; you need an equality-test:
                        ;; default is #'eql (for simple numbers or symbols this is sufficient)
                        ;; - for numbers only #'=
                        ;; - for characters only #'char=
                        ;; - for strings only #'string=
                        ;; - for lists #'equal
                        ;; - for nearly everything #'equalp (case insensitive for char/strings!)
                        ;; then you need also a sorting tester:
                        ;; - increasing number: #'<
                        ;; - decreasing number: #'>
                        ;; - increasing char: #'char<
                        ;; - decreasing char: #'char>
                        ;; - increasing strings: #'string<
                        ;; - decreasing strings: #'string>
                        ;; - other cases I haven't think of - does somebody have an idea?
                        ;; (one could sort by length of element etc.)
                        ;; so sort-test should be a diadic function (function taking 2 arguments to compare)
                        ;; then you also need an accessor function
                        ;; so, how withing each element the to-be-sorted element should be accessed
                        ;; for this, I prepared the `id` - identity - function because this is the
                        ;; sort-key when simple comparison of the elements of the two lists
                        ;; should be compared - and this function is also used for testing
                        ;; for equality in the inner `.isect` function.
                        (defun isect (lst-1 lst-2 &key (equality-test #'eql) (sort-test #'<) (sort-key #'id))
                        (let ((lst-1-sorted (stable-sort lst-1 sort-test :key sort-key))
                        (lst-2-sorted (stable-sort lst-2 sort-test :key sort-key)))
                        (labels ((.isect (l1 l2 acc)
                        (cond ((or (null l1) (null l2)) (nreverse acc))
                        (t (let ((l1-element (funcall sort-key (car l1)))
                        (l2-element (funcall sort-key (car l2))))
                        (cond ((funcall sort-test l1-element l2-element)
                        (.isect (cdr l1) l2 acc))
                        ((funcall equality-test l1-element l2-element)
                        (.isect (cdr l1) (cdr l2) (cons (car l1) acc)))
                        (t (.isect l1 (cdr l2) acc))))))))
                        (.isect lst-1-sorted lst-2-sorted '()))))


                        Simple tests:



                        (isect '(0 1 2 3 4 5 6) '(9 0 3 5 12 24 8 6))
                        ;; => (0 3 5 6)

                        (isect '(#a #c #h #t #e #r #b #a #h #n)
                        '(#a #m #s #e #l #s #t #a #r)
                        :equality-test #'char=
                        :sort-test #'char<
                        :key #'id)
                        ;; => (#a #a #e #r #t)

                        (isect '("this" "is" "just" "a" "boring" "test")
                        '("this" "boring" "strings" "are" "to" "be" "intersected")
                        :equality-test #'string=
                        :sort-test #'string<
                        :key #'id)
                        ;; => ("boring" "this")





                        share|improve this answer




























                          0














                          ;; the key function for simple lists
                          (defun id (x) x)

                          ;; the intersect function for two lists
                          ;; with sorting included:
                          ;; you need an equality-test:
                          ;; default is #'eql (for simple numbers or symbols this is sufficient)
                          ;; - for numbers only #'=
                          ;; - for characters only #'char=
                          ;; - for strings only #'string=
                          ;; - for lists #'equal
                          ;; - for nearly everything #'equalp (case insensitive for char/strings!)
                          ;; then you need also a sorting tester:
                          ;; - increasing number: #'<
                          ;; - decreasing number: #'>
                          ;; - increasing char: #'char<
                          ;; - decreasing char: #'char>
                          ;; - increasing strings: #'string<
                          ;; - decreasing strings: #'string>
                          ;; - other cases I haven't think of - does somebody have an idea?
                          ;; (one could sort by length of element etc.)
                          ;; so sort-test should be a diadic function (function taking 2 arguments to compare)
                          ;; then you also need an accessor function
                          ;; so, how withing each element the to-be-sorted element should be accessed
                          ;; for this, I prepared the `id` - identity - function because this is the
                          ;; sort-key when simple comparison of the elements of the two lists
                          ;; should be compared - and this function is also used for testing
                          ;; for equality in the inner `.isect` function.
                          (defun isect (lst-1 lst-2 &key (equality-test #'eql) (sort-test #'<) (sort-key #'id))
                          (let ((lst-1-sorted (stable-sort lst-1 sort-test :key sort-key))
                          (lst-2-sorted (stable-sort lst-2 sort-test :key sort-key)))
                          (labels ((.isect (l1 l2 acc)
                          (cond ((or (null l1) (null l2)) (nreverse acc))
                          (t (let ((l1-element (funcall sort-key (car l1)))
                          (l2-element (funcall sort-key (car l2))))
                          (cond ((funcall sort-test l1-element l2-element)
                          (.isect (cdr l1) l2 acc))
                          ((funcall equality-test l1-element l2-element)
                          (.isect (cdr l1) (cdr l2) (cons (car l1) acc)))
                          (t (.isect l1 (cdr l2) acc))))))))
                          (.isect lst-1-sorted lst-2-sorted '()))))


                          Simple tests:



                          (isect '(0 1 2 3 4 5 6) '(9 0 3 5 12 24 8 6))
                          ;; => (0 3 5 6)

                          (isect '(#a #c #h #t #e #r #b #a #h #n)
                          '(#a #m #s #e #l #s #t #a #r)
                          :equality-test #'char=
                          :sort-test #'char<
                          :key #'id)
                          ;; => (#a #a #e #r #t)

                          (isect '("this" "is" "just" "a" "boring" "test")
                          '("this" "boring" "strings" "are" "to" "be" "intersected")
                          :equality-test #'string=
                          :sort-test #'string<
                          :key #'id)
                          ;; => ("boring" "this")





                          share|improve this answer


























                            0












                            0








                            0







                            ;; the key function for simple lists
                            (defun id (x) x)

                            ;; the intersect function for two lists
                            ;; with sorting included:
                            ;; you need an equality-test:
                            ;; default is #'eql (for simple numbers or symbols this is sufficient)
                            ;; - for numbers only #'=
                            ;; - for characters only #'char=
                            ;; - for strings only #'string=
                            ;; - for lists #'equal
                            ;; - for nearly everything #'equalp (case insensitive for char/strings!)
                            ;; then you need also a sorting tester:
                            ;; - increasing number: #'<
                            ;; - decreasing number: #'>
                            ;; - increasing char: #'char<
                            ;; - decreasing char: #'char>
                            ;; - increasing strings: #'string<
                            ;; - decreasing strings: #'string>
                            ;; - other cases I haven't think of - does somebody have an idea?
                            ;; (one could sort by length of element etc.)
                            ;; so sort-test should be a diadic function (function taking 2 arguments to compare)
                            ;; then you also need an accessor function
                            ;; so, how withing each element the to-be-sorted element should be accessed
                            ;; for this, I prepared the `id` - identity - function because this is the
                            ;; sort-key when simple comparison of the elements of the two lists
                            ;; should be compared - and this function is also used for testing
                            ;; for equality in the inner `.isect` function.
                            (defun isect (lst-1 lst-2 &key (equality-test #'eql) (sort-test #'<) (sort-key #'id))
                            (let ((lst-1-sorted (stable-sort lst-1 sort-test :key sort-key))
                            (lst-2-sorted (stable-sort lst-2 sort-test :key sort-key)))
                            (labels ((.isect (l1 l2 acc)
                            (cond ((or (null l1) (null l2)) (nreverse acc))
                            (t (let ((l1-element (funcall sort-key (car l1)))
                            (l2-element (funcall sort-key (car l2))))
                            (cond ((funcall sort-test l1-element l2-element)
                            (.isect (cdr l1) l2 acc))
                            ((funcall equality-test l1-element l2-element)
                            (.isect (cdr l1) (cdr l2) (cons (car l1) acc)))
                            (t (.isect l1 (cdr l2) acc))))))))
                            (.isect lst-1-sorted lst-2-sorted '()))))


                            Simple tests:



                            (isect '(0 1 2 3 4 5 6) '(9 0 3 5 12 24 8 6))
                            ;; => (0 3 5 6)

                            (isect '(#a #c #h #t #e #r #b #a #h #n)
                            '(#a #m #s #e #l #s #t #a #r)
                            :equality-test #'char=
                            :sort-test #'char<
                            :key #'id)
                            ;; => (#a #a #e #r #t)

                            (isect '("this" "is" "just" "a" "boring" "test")
                            '("this" "boring" "strings" "are" "to" "be" "intersected")
                            :equality-test #'string=
                            :sort-test #'string<
                            :key #'id)
                            ;; => ("boring" "this")





                            share|improve this answer













                            ;; the key function for simple lists
                            (defun id (x) x)

                            ;; the intersect function for two lists
                            ;; with sorting included:
                            ;; you need an equality-test:
                            ;; default is #'eql (for simple numbers or symbols this is sufficient)
                            ;; - for numbers only #'=
                            ;; - for characters only #'char=
                            ;; - for strings only #'string=
                            ;; - for lists #'equal
                            ;; - for nearly everything #'equalp (case insensitive for char/strings!)
                            ;; then you need also a sorting tester:
                            ;; - increasing number: #'<
                            ;; - decreasing number: #'>
                            ;; - increasing char: #'char<
                            ;; - decreasing char: #'char>
                            ;; - increasing strings: #'string<
                            ;; - decreasing strings: #'string>
                            ;; - other cases I haven't think of - does somebody have an idea?
                            ;; (one could sort by length of element etc.)
                            ;; so sort-test should be a diadic function (function taking 2 arguments to compare)
                            ;; then you also need an accessor function
                            ;; so, how withing each element the to-be-sorted element should be accessed
                            ;; for this, I prepared the `id` - identity - function because this is the
                            ;; sort-key when simple comparison of the elements of the two lists
                            ;; should be compared - and this function is also used for testing
                            ;; for equality in the inner `.isect` function.
                            (defun isect (lst-1 lst-2 &key (equality-test #'eql) (sort-test #'<) (sort-key #'id))
                            (let ((lst-1-sorted (stable-sort lst-1 sort-test :key sort-key))
                            (lst-2-sorted (stable-sort lst-2 sort-test :key sort-key)))
                            (labels ((.isect (l1 l2 acc)
                            (cond ((or (null l1) (null l2)) (nreverse acc))
                            (t (let ((l1-element (funcall sort-key (car l1)))
                            (l2-element (funcall sort-key (car l2))))
                            (cond ((funcall sort-test l1-element l2-element)
                            (.isect (cdr l1) l2 acc))
                            ((funcall equality-test l1-element l2-element)
                            (.isect (cdr l1) (cdr l2) (cons (car l1) acc)))
                            (t (.isect l1 (cdr l2) acc))))))))
                            (.isect lst-1-sorted lst-2-sorted '()))))


                            Simple tests:



                            (isect '(0 1 2 3 4 5 6) '(9 0 3 5 12 24 8 6))
                            ;; => (0 3 5 6)

                            (isect '(#a #c #h #t #e #r #b #a #h #n)
                            '(#a #m #s #e #l #s #t #a #r)
                            :equality-test #'char=
                            :sort-test #'char<
                            :key #'id)
                            ;; => (#a #a #e #r #t)

                            (isect '("this" "is" "just" "a" "boring" "test")
                            '("this" "boring" "strings" "are" "to" "be" "intersected")
                            :equality-test #'string=
                            :sort-test #'string<
                            :key #'id)
                            ;; => ("boring" "this")






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Nov 16 '18 at 6:32









                            Gwang-Jin KimGwang-Jin Kim

                            2,416116




                            2,416116






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53209247%2flisp-intersection-of-lists%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Bressuire

                                Vorschmack

                                Quarantine