Find if one list is a subsequence of another












3












$begingroup$


So the problem of verifying if a list is a subsequence of another came up in a discussion, and I wrote code that seems to work (I haven't rigorously tested it).



IsSubequence.py



def is_subsequence(lst1, lst2):
"""
* Finds if a list is a subsequence of another.

* Params:
* `lst1` (`list`): The candidate subsequence.
* `lst2` (`list`): The parent list.
* Return:
* (`bool`): A boolean variable indicating whether `lst1` is a subsequence of `lst2`.
"""
l1, l2 = len(lst1), len(lst2)
if l1 > l2: #`l1` must be <= `l2` for `lst1` to be a subsequence of `lst2`.
return False
i = j = 0
d1, d2 = l1, l2
while i < l1 and j < l2:
while lst1[i] != lst2[j]:
j += 1
d2 -= 1
if d1 > d2: #At this point, `lst1` cannot a subsequence of `lst2`.
return False
i, j, d1, d2 = i+1, j+1, d1-1, d2-1
if d1 > d2:
return False
return True


I'm primarily concerned about performance.










share|improve this question











$endgroup$

















    3












    $begingroup$


    So the problem of verifying if a list is a subsequence of another came up in a discussion, and I wrote code that seems to work (I haven't rigorously tested it).



    IsSubequence.py



    def is_subsequence(lst1, lst2):
    """
    * Finds if a list is a subsequence of another.

    * Params:
    * `lst1` (`list`): The candidate subsequence.
    * `lst2` (`list`): The parent list.
    * Return:
    * (`bool`): A boolean variable indicating whether `lst1` is a subsequence of `lst2`.
    """
    l1, l2 = len(lst1), len(lst2)
    if l1 > l2: #`l1` must be <= `l2` for `lst1` to be a subsequence of `lst2`.
    return False
    i = j = 0
    d1, d2 = l1, l2
    while i < l1 and j < l2:
    while lst1[i] != lst2[j]:
    j += 1
    d2 -= 1
    if d1 > d2: #At this point, `lst1` cannot a subsequence of `lst2`.
    return False
    i, j, d1, d2 = i+1, j+1, d1-1, d2-1
    if d1 > d2:
    return False
    return True


    I'm primarily concerned about performance.










    share|improve this question











    $endgroup$















      3












      3








      3





      $begingroup$


      So the problem of verifying if a list is a subsequence of another came up in a discussion, and I wrote code that seems to work (I haven't rigorously tested it).



      IsSubequence.py



      def is_subsequence(lst1, lst2):
      """
      * Finds if a list is a subsequence of another.

      * Params:
      * `lst1` (`list`): The candidate subsequence.
      * `lst2` (`list`): The parent list.
      * Return:
      * (`bool`): A boolean variable indicating whether `lst1` is a subsequence of `lst2`.
      """
      l1, l2 = len(lst1), len(lst2)
      if l1 > l2: #`l1` must be <= `l2` for `lst1` to be a subsequence of `lst2`.
      return False
      i = j = 0
      d1, d2 = l1, l2
      while i < l1 and j < l2:
      while lst1[i] != lst2[j]:
      j += 1
      d2 -= 1
      if d1 > d2: #At this point, `lst1` cannot a subsequence of `lst2`.
      return False
      i, j, d1, d2 = i+1, j+1, d1-1, d2-1
      if d1 > d2:
      return False
      return True


      I'm primarily concerned about performance.










      share|improve this question











      $endgroup$




      So the problem of verifying if a list is a subsequence of another came up in a discussion, and I wrote code that seems to work (I haven't rigorously tested it).



      IsSubequence.py



      def is_subsequence(lst1, lst2):
      """
      * Finds if a list is a subsequence of another.

      * Params:
      * `lst1` (`list`): The candidate subsequence.
      * `lst2` (`list`): The parent list.
      * Return:
      * (`bool`): A boolean variable indicating whether `lst1` is a subsequence of `lst2`.
      """
      l1, l2 = len(lst1), len(lst2)
      if l1 > l2: #`l1` must be <= `l2` for `lst1` to be a subsequence of `lst2`.
      return False
      i = j = 0
      d1, d2 = l1, l2
      while i < l1 and j < l2:
      while lst1[i] != lst2[j]:
      j += 1
      d2 -= 1
      if d1 > d2: #At this point, `lst1` cannot a subsequence of `lst2`.
      return False
      i, j, d1, d2 = i+1, j+1, d1-1, d2-1
      if d1 > d2:
      return False
      return True


      I'm primarily concerned about performance.







      python performance beginner algorithm array






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 8 hours ago









      Mast

      7,53863788




      7,53863788










      asked 8 hours ago









      Tobi AlafinTobi Alafin

      57019




      57019






















          1 Answer
          1






          active

          oldest

          votes


















          9












          $begingroup$

          Review





          • Testing




            (I haven't rigorously tested it).




            Well you should write some test to ensure validity of the function. So even after changes you can be sure it will still work. doctest is a pretty nice module to use, and is a nice extension of your docstring




          • Naming



            Variables should have descriptive names!



            lst1, lst2 if it wasn't for that docstring I would not have known what is the subseq and the parent, so instead I propose to rename them to needle and haystack here the intent is more clear



            Same goes for d1, d2... I can see that they are the remaining length of the list, but it is hard to tell from the variable name.




          • for is considered more Pythonic vs while



            For loops are Pythons greatest feature IMHO, they are easy to read and short to write



            You should start writing for loops instead of a while, "Loop like a native" might be an interesting talk to view




          • Too many assignments in a line



            Might be preference, but I find this line hard to read:



            i, j, d1, d2 = i+1, j+1, d1-1, d2-1



            There are too many values with not enough descriptive names on this line




          Alternative



          We can instead loop over the haystack and use slicing to compare the sliced haystack with the needle, lastly top it off with the any keyword and write some tests with the doctest module



          import doctest

          def is_subsequence(needle, haystack):
          """
          Finds if a list is a subsequence of another.

          * args
          needle: the candidate subsequence
          haystack: the parent list

          * returns
          boolean

          >>> is_subsequence([1, 2, 3, 4], [1, 2, 3, 4, 5, 6])
          True
          >>> is_subsequence([1, 2, 3, 4], [1, 2, 3, 5, 6])
          False
          >>> is_subsequence([6], [1, 2, 3, 5, 6])
          True
          >>> is_subsequence([5, 6], [1, 2, 3, 5, 6])
          True
          >>> is_subsequence([[5, 6], 7], [1, 2, 3, [5, 6], 7])
          True
          >>> is_subsequence([1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, [5, 6], 7])
          False
          """
          return any(
          haystack[i:i+len(needle)] == needle
          for i in range(len(haystack) - len(needle) + 1)
          )

          if __name__ == '__main__':
          doctest.testmod()





          share|improve this answer









          $endgroup$













            Your Answer





            StackExchange.ifUsing("editor", function () {
            return StackExchange.using("mathjaxEditing", function () {
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            });
            });
            }, "mathjax-editing");

            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: "196"
            };
            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: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            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%2fcodereview.stackexchange.com%2fquestions%2f215324%2ffind-if-one-list-is-a-subsequence-of-another%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            9












            $begingroup$

            Review





            • Testing




              (I haven't rigorously tested it).




              Well you should write some test to ensure validity of the function. So even after changes you can be sure it will still work. doctest is a pretty nice module to use, and is a nice extension of your docstring




            • Naming



              Variables should have descriptive names!



              lst1, lst2 if it wasn't for that docstring I would not have known what is the subseq and the parent, so instead I propose to rename them to needle and haystack here the intent is more clear



              Same goes for d1, d2... I can see that they are the remaining length of the list, but it is hard to tell from the variable name.




            • for is considered more Pythonic vs while



              For loops are Pythons greatest feature IMHO, they are easy to read and short to write



              You should start writing for loops instead of a while, "Loop like a native" might be an interesting talk to view




            • Too many assignments in a line



              Might be preference, but I find this line hard to read:



              i, j, d1, d2 = i+1, j+1, d1-1, d2-1



              There are too many values with not enough descriptive names on this line




            Alternative



            We can instead loop over the haystack and use slicing to compare the sliced haystack with the needle, lastly top it off with the any keyword and write some tests with the doctest module



            import doctest

            def is_subsequence(needle, haystack):
            """
            Finds if a list is a subsequence of another.

            * args
            needle: the candidate subsequence
            haystack: the parent list

            * returns
            boolean

            >>> is_subsequence([1, 2, 3, 4], [1, 2, 3, 4, 5, 6])
            True
            >>> is_subsequence([1, 2, 3, 4], [1, 2, 3, 5, 6])
            False
            >>> is_subsequence([6], [1, 2, 3, 5, 6])
            True
            >>> is_subsequence([5, 6], [1, 2, 3, 5, 6])
            True
            >>> is_subsequence([[5, 6], 7], [1, 2, 3, [5, 6], 7])
            True
            >>> is_subsequence([1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, [5, 6], 7])
            False
            """
            return any(
            haystack[i:i+len(needle)] == needle
            for i in range(len(haystack) - len(needle) + 1)
            )

            if __name__ == '__main__':
            doctest.testmod()





            share|improve this answer









            $endgroup$


















              9












              $begingroup$

              Review





              • Testing




                (I haven't rigorously tested it).




                Well you should write some test to ensure validity of the function. So even after changes you can be sure it will still work. doctest is a pretty nice module to use, and is a nice extension of your docstring




              • Naming



                Variables should have descriptive names!



                lst1, lst2 if it wasn't for that docstring I would not have known what is the subseq and the parent, so instead I propose to rename them to needle and haystack here the intent is more clear



                Same goes for d1, d2... I can see that they are the remaining length of the list, but it is hard to tell from the variable name.




              • for is considered more Pythonic vs while



                For loops are Pythons greatest feature IMHO, they are easy to read and short to write



                You should start writing for loops instead of a while, "Loop like a native" might be an interesting talk to view




              • Too many assignments in a line



                Might be preference, but I find this line hard to read:



                i, j, d1, d2 = i+1, j+1, d1-1, d2-1



                There are too many values with not enough descriptive names on this line




              Alternative



              We can instead loop over the haystack and use slicing to compare the sliced haystack with the needle, lastly top it off with the any keyword and write some tests with the doctest module



              import doctest

              def is_subsequence(needle, haystack):
              """
              Finds if a list is a subsequence of another.

              * args
              needle: the candidate subsequence
              haystack: the parent list

              * returns
              boolean

              >>> is_subsequence([1, 2, 3, 4], [1, 2, 3, 4, 5, 6])
              True
              >>> is_subsequence([1, 2, 3, 4], [1, 2, 3, 5, 6])
              False
              >>> is_subsequence([6], [1, 2, 3, 5, 6])
              True
              >>> is_subsequence([5, 6], [1, 2, 3, 5, 6])
              True
              >>> is_subsequence([[5, 6], 7], [1, 2, 3, [5, 6], 7])
              True
              >>> is_subsequence([1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, [5, 6], 7])
              False
              """
              return any(
              haystack[i:i+len(needle)] == needle
              for i in range(len(haystack) - len(needle) + 1)
              )

              if __name__ == '__main__':
              doctest.testmod()





              share|improve this answer









              $endgroup$
















                9












                9








                9





                $begingroup$

                Review





                • Testing




                  (I haven't rigorously tested it).




                  Well you should write some test to ensure validity of the function. So even after changes you can be sure it will still work. doctest is a pretty nice module to use, and is a nice extension of your docstring




                • Naming



                  Variables should have descriptive names!



                  lst1, lst2 if it wasn't for that docstring I would not have known what is the subseq and the parent, so instead I propose to rename them to needle and haystack here the intent is more clear



                  Same goes for d1, d2... I can see that they are the remaining length of the list, but it is hard to tell from the variable name.




                • for is considered more Pythonic vs while



                  For loops are Pythons greatest feature IMHO, they are easy to read and short to write



                  You should start writing for loops instead of a while, "Loop like a native" might be an interesting talk to view




                • Too many assignments in a line



                  Might be preference, but I find this line hard to read:



                  i, j, d1, d2 = i+1, j+1, d1-1, d2-1



                  There are too many values with not enough descriptive names on this line




                Alternative



                We can instead loop over the haystack and use slicing to compare the sliced haystack with the needle, lastly top it off with the any keyword and write some tests with the doctest module



                import doctest

                def is_subsequence(needle, haystack):
                """
                Finds if a list is a subsequence of another.

                * args
                needle: the candidate subsequence
                haystack: the parent list

                * returns
                boolean

                >>> is_subsequence([1, 2, 3, 4], [1, 2, 3, 4, 5, 6])
                True
                >>> is_subsequence([1, 2, 3, 4], [1, 2, 3, 5, 6])
                False
                >>> is_subsequence([6], [1, 2, 3, 5, 6])
                True
                >>> is_subsequence([5, 6], [1, 2, 3, 5, 6])
                True
                >>> is_subsequence([[5, 6], 7], [1, 2, 3, [5, 6], 7])
                True
                >>> is_subsequence([1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, [5, 6], 7])
                False
                """
                return any(
                haystack[i:i+len(needle)] == needle
                for i in range(len(haystack) - len(needle) + 1)
                )

                if __name__ == '__main__':
                doctest.testmod()





                share|improve this answer









                $endgroup$



                Review





                • Testing




                  (I haven't rigorously tested it).




                  Well you should write some test to ensure validity of the function. So even after changes you can be sure it will still work. doctest is a pretty nice module to use, and is a nice extension of your docstring




                • Naming



                  Variables should have descriptive names!



                  lst1, lst2 if it wasn't for that docstring I would not have known what is the subseq and the parent, so instead I propose to rename them to needle and haystack here the intent is more clear



                  Same goes for d1, d2... I can see that they are the remaining length of the list, but it is hard to tell from the variable name.




                • for is considered more Pythonic vs while



                  For loops are Pythons greatest feature IMHO, they are easy to read and short to write



                  You should start writing for loops instead of a while, "Loop like a native" might be an interesting talk to view




                • Too many assignments in a line



                  Might be preference, but I find this line hard to read:



                  i, j, d1, d2 = i+1, j+1, d1-1, d2-1



                  There are too many values with not enough descriptive names on this line




                Alternative



                We can instead loop over the haystack and use slicing to compare the sliced haystack with the needle, lastly top it off with the any keyword and write some tests with the doctest module



                import doctest

                def is_subsequence(needle, haystack):
                """
                Finds if a list is a subsequence of another.

                * args
                needle: the candidate subsequence
                haystack: the parent list

                * returns
                boolean

                >>> is_subsequence([1, 2, 3, 4], [1, 2, 3, 4, 5, 6])
                True
                >>> is_subsequence([1, 2, 3, 4], [1, 2, 3, 5, 6])
                False
                >>> is_subsequence([6], [1, 2, 3, 5, 6])
                True
                >>> is_subsequence([5, 6], [1, 2, 3, 5, 6])
                True
                >>> is_subsequence([[5, 6], 7], [1, 2, 3, [5, 6], 7])
                True
                >>> is_subsequence([1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, [5, 6], 7])
                False
                """
                return any(
                haystack[i:i+len(needle)] == needle
                for i in range(len(haystack) - len(needle) + 1)
                )

                if __name__ == '__main__':
                doctest.testmod()






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered 7 hours ago









                LudisposedLudisposed

                8,55722164




                8,55722164






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Code Review Stack Exchange!


                    • 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.


                    Use MathJax to format equations. MathJax reference.


                    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%2fcodereview.stackexchange.com%2fquestions%2f215324%2ffind-if-one-list-is-a-subsequence-of-another%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

                    Callistus I

                    Tabula Rosettana

                    How to label and detect the document text images