List comprehension to find matching parens










1















I'm trying to come up with a list comprehension that will match open and close parens. So far I have these two statements which grab two lists of open and close parens separately



my_str = "hanz(and(franz/bob())+ 7) + tom(2)"


Grab idx of open parens:



[ i for i,c in enumerate(my_str) if c == '(']

# [4, 8, 18, 31]


Grab idx of close parens:



[ i for i,c in enumerate(my_str) if c == ')']

# [19, 20, 24, 33]


What I would like is one handy comprehension that could give me a list of pairs corresponding to each match pair of parens



i.e.



[ ???? for i,c in enumerate(my_str) ???]

# [(4,24), (8,20), (18,19), (31,33)]









share|improve this question

















  • 6





    This isn't really a job for a list comprehension; is there a reason for it? It's extremely easy with a loop and a stack.

    – Tordek
    Nov 15 '18 at 2:54















1















I'm trying to come up with a list comprehension that will match open and close parens. So far I have these two statements which grab two lists of open and close parens separately



my_str = "hanz(and(franz/bob())+ 7) + tom(2)"


Grab idx of open parens:



[ i for i,c in enumerate(my_str) if c == '(']

# [4, 8, 18, 31]


Grab idx of close parens:



[ i for i,c in enumerate(my_str) if c == ')']

# [19, 20, 24, 33]


What I would like is one handy comprehension that could give me a list of pairs corresponding to each match pair of parens



i.e.



[ ???? for i,c in enumerate(my_str) ???]

# [(4,24), (8,20), (18,19), (31,33)]









share|improve this question

















  • 6





    This isn't really a job for a list comprehension; is there a reason for it? It's extremely easy with a loop and a stack.

    – Tordek
    Nov 15 '18 at 2:54













1












1








1








I'm trying to come up with a list comprehension that will match open and close parens. So far I have these two statements which grab two lists of open and close parens separately



my_str = "hanz(and(franz/bob())+ 7) + tom(2)"


Grab idx of open parens:



[ i for i,c in enumerate(my_str) if c == '(']

# [4, 8, 18, 31]


Grab idx of close parens:



[ i for i,c in enumerate(my_str) if c == ')']

# [19, 20, 24, 33]


What I would like is one handy comprehension that could give me a list of pairs corresponding to each match pair of parens



i.e.



[ ???? for i,c in enumerate(my_str) ???]

# [(4,24), (8,20), (18,19), (31,33)]









share|improve this question














I'm trying to come up with a list comprehension that will match open and close parens. So far I have these two statements which grab two lists of open and close parens separately



my_str = "hanz(and(franz/bob())+ 7) + tom(2)"


Grab idx of open parens:



[ i for i,c in enumerate(my_str) if c == '(']

# [4, 8, 18, 31]


Grab idx of close parens:



[ i for i,c in enumerate(my_str) if c == ')']

# [19, 20, 24, 33]


What I would like is one handy comprehension that could give me a list of pairs corresponding to each match pair of parens



i.e.



[ ???? for i,c in enumerate(my_str) ???]

# [(4,24), (8,20), (18,19), (31,33)]






python list-comprehension






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 15 '18 at 2:37









darkpbjdarkpbj

1,12521326




1,12521326







  • 6





    This isn't really a job for a list comprehension; is there a reason for it? It's extremely easy with a loop and a stack.

    – Tordek
    Nov 15 '18 at 2:54












  • 6





    This isn't really a job for a list comprehension; is there a reason for it? It's extremely easy with a loop and a stack.

    – Tordek
    Nov 15 '18 at 2:54







6




6





This isn't really a job for a list comprehension; is there a reason for it? It's extremely easy with a loop and a stack.

– Tordek
Nov 15 '18 at 2:54





This isn't really a job for a list comprehension; is there a reason for it? It's extremely easy with a loop and a stack.

– Tordek
Nov 15 '18 at 2:54












2 Answers
2






active

oldest

votes


















0














Like @Tordek mentioned, though not impossible this is not very practical,



For the sake of completeness however, here's a solution:



my_str = "hanz(and(franz/bob())+ 7) + tom(2)"

pt_arr = [ 1 if c == '(' else -1 for i,c in enumerate(my_str ) if c == ')' or c == '(']
idx_arr = [ i for i,c in enumerate(my_str ) if c == ')' or c == '(']

[(idx_arr[strt_idx],idx_arr[strt_idx + [j for j,d in enumerate([ sum(pt_arr[strt_idx:i + 1]) for i,c in enumerate(pt_arr) if i >= strt_idx]) if d == 0][0]]) for strt_idx,f in enumerate(pt_arr) if f == 1]

# [(4,24), (8,20), (18,19), (31,33)]





share|improve this answer






























    0














    As mentioned in comments, the proper and simple way to do this is using a stack:



    my_str = "hanz(and(franz/bob())+ 7) + tom(2)"
    stack =
    parens =
    for i, c in enumerate(my_str):
    if c == "(":
    stack.append(i)
    elif c == ")":
    parens.append((stack.pop(), i))
    print(parens) # [(18, 19), (8, 20), (4, 24), (31, 33)]


    But if you value one-liners more than readability or coding conventions, you could also cram that into a list comprehensions with side effects:



    stack = 
    parens = [(stack.pop(), i) for i, c in enumerate(my_str)
    if c == "(" and stack.append(i) or c == ")"]
    print(parens) # [(18, 19), (8, 20), (4, 24), (31, 33)]


    This uses the fact that and and or are short-circuit-evaluated, thus it will append items only if c == "(", but then fail because append return None, and only add elements to the results if the second condition, c == ")" is true, popping the position of the most recent ( from the stack.



    At least, it is not a total abuse of list comprehensions, as the result is not discarded but actually the desired result, and it's probably still easier to comprehend than the three list comprehensions that you have (although those work without side effects), but the better solution for a "handy" way to do this would be: Make it a function, than it does not matter how many lines it has.






    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%2f53311626%2flist-comprehension-to-find-matching-parens%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      0














      Like @Tordek mentioned, though not impossible this is not very practical,



      For the sake of completeness however, here's a solution:



      my_str = "hanz(and(franz/bob())+ 7) + tom(2)"

      pt_arr = [ 1 if c == '(' else -1 for i,c in enumerate(my_str ) if c == ')' or c == '(']
      idx_arr = [ i for i,c in enumerate(my_str ) if c == ')' or c == '(']

      [(idx_arr[strt_idx],idx_arr[strt_idx + [j for j,d in enumerate([ sum(pt_arr[strt_idx:i + 1]) for i,c in enumerate(pt_arr) if i >= strt_idx]) if d == 0][0]]) for strt_idx,f in enumerate(pt_arr) if f == 1]

      # [(4,24), (8,20), (18,19), (31,33)]





      share|improve this answer



























        0














        Like @Tordek mentioned, though not impossible this is not very practical,



        For the sake of completeness however, here's a solution:



        my_str = "hanz(and(franz/bob())+ 7) + tom(2)"

        pt_arr = [ 1 if c == '(' else -1 for i,c in enumerate(my_str ) if c == ')' or c == '(']
        idx_arr = [ i for i,c in enumerate(my_str ) if c == ')' or c == '(']

        [(idx_arr[strt_idx],idx_arr[strt_idx + [j for j,d in enumerate([ sum(pt_arr[strt_idx:i + 1]) for i,c in enumerate(pt_arr) if i >= strt_idx]) if d == 0][0]]) for strt_idx,f in enumerate(pt_arr) if f == 1]

        # [(4,24), (8,20), (18,19), (31,33)]





        share|improve this answer

























          0












          0








          0







          Like @Tordek mentioned, though not impossible this is not very practical,



          For the sake of completeness however, here's a solution:



          my_str = "hanz(and(franz/bob())+ 7) + tom(2)"

          pt_arr = [ 1 if c == '(' else -1 for i,c in enumerate(my_str ) if c == ')' or c == '(']
          idx_arr = [ i for i,c in enumerate(my_str ) if c == ')' or c == '(']

          [(idx_arr[strt_idx],idx_arr[strt_idx + [j for j,d in enumerate([ sum(pt_arr[strt_idx:i + 1]) for i,c in enumerate(pt_arr) if i >= strt_idx]) if d == 0][0]]) for strt_idx,f in enumerate(pt_arr) if f == 1]

          # [(4,24), (8,20), (18,19), (31,33)]





          share|improve this answer













          Like @Tordek mentioned, though not impossible this is not very practical,



          For the sake of completeness however, here's a solution:



          my_str = "hanz(and(franz/bob())+ 7) + tom(2)"

          pt_arr = [ 1 if c == '(' else -1 for i,c in enumerate(my_str ) if c == ')' or c == '(']
          idx_arr = [ i for i,c in enumerate(my_str ) if c == ')' or c == '(']

          [(idx_arr[strt_idx],idx_arr[strt_idx + [j for j,d in enumerate([ sum(pt_arr[strt_idx:i + 1]) for i,c in enumerate(pt_arr) if i >= strt_idx]) if d == 0][0]]) for strt_idx,f in enumerate(pt_arr) if f == 1]

          # [(4,24), (8,20), (18,19), (31,33)]






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 15 '18 at 16:37









          darkpbjdarkpbj

          1,12521326




          1,12521326























              0














              As mentioned in comments, the proper and simple way to do this is using a stack:



              my_str = "hanz(and(franz/bob())+ 7) + tom(2)"
              stack =
              parens =
              for i, c in enumerate(my_str):
              if c == "(":
              stack.append(i)
              elif c == ")":
              parens.append((stack.pop(), i))
              print(parens) # [(18, 19), (8, 20), (4, 24), (31, 33)]


              But if you value one-liners more than readability or coding conventions, you could also cram that into a list comprehensions with side effects:



              stack = 
              parens = [(stack.pop(), i) for i, c in enumerate(my_str)
              if c == "(" and stack.append(i) or c == ")"]
              print(parens) # [(18, 19), (8, 20), (4, 24), (31, 33)]


              This uses the fact that and and or are short-circuit-evaluated, thus it will append items only if c == "(", but then fail because append return None, and only add elements to the results if the second condition, c == ")" is true, popping the position of the most recent ( from the stack.



              At least, it is not a total abuse of list comprehensions, as the result is not discarded but actually the desired result, and it's probably still easier to comprehend than the three list comprehensions that you have (although those work without side effects), but the better solution for a "handy" way to do this would be: Make it a function, than it does not matter how many lines it has.






              share|improve this answer





























                0














                As mentioned in comments, the proper and simple way to do this is using a stack:



                my_str = "hanz(and(franz/bob())+ 7) + tom(2)"
                stack =
                parens =
                for i, c in enumerate(my_str):
                if c == "(":
                stack.append(i)
                elif c == ")":
                parens.append((stack.pop(), i))
                print(parens) # [(18, 19), (8, 20), (4, 24), (31, 33)]


                But if you value one-liners more than readability or coding conventions, you could also cram that into a list comprehensions with side effects:



                stack = 
                parens = [(stack.pop(), i) for i, c in enumerate(my_str)
                if c == "(" and stack.append(i) or c == ")"]
                print(parens) # [(18, 19), (8, 20), (4, 24), (31, 33)]


                This uses the fact that and and or are short-circuit-evaluated, thus it will append items only if c == "(", but then fail because append return None, and only add elements to the results if the second condition, c == ")" is true, popping the position of the most recent ( from the stack.



                At least, it is not a total abuse of list comprehensions, as the result is not discarded but actually the desired result, and it's probably still easier to comprehend than the three list comprehensions that you have (although those work without side effects), but the better solution for a "handy" way to do this would be: Make it a function, than it does not matter how many lines it has.






                share|improve this answer



























                  0












                  0








                  0







                  As mentioned in comments, the proper and simple way to do this is using a stack:



                  my_str = "hanz(and(franz/bob())+ 7) + tom(2)"
                  stack =
                  parens =
                  for i, c in enumerate(my_str):
                  if c == "(":
                  stack.append(i)
                  elif c == ")":
                  parens.append((stack.pop(), i))
                  print(parens) # [(18, 19), (8, 20), (4, 24), (31, 33)]


                  But if you value one-liners more than readability or coding conventions, you could also cram that into a list comprehensions with side effects:



                  stack = 
                  parens = [(stack.pop(), i) for i, c in enumerate(my_str)
                  if c == "(" and stack.append(i) or c == ")"]
                  print(parens) # [(18, 19), (8, 20), (4, 24), (31, 33)]


                  This uses the fact that and and or are short-circuit-evaluated, thus it will append items only if c == "(", but then fail because append return None, and only add elements to the results if the second condition, c == ")" is true, popping the position of the most recent ( from the stack.



                  At least, it is not a total abuse of list comprehensions, as the result is not discarded but actually the desired result, and it's probably still easier to comprehend than the three list comprehensions that you have (although those work without side effects), but the better solution for a "handy" way to do this would be: Make it a function, than it does not matter how many lines it has.






                  share|improve this answer















                  As mentioned in comments, the proper and simple way to do this is using a stack:



                  my_str = "hanz(and(franz/bob())+ 7) + tom(2)"
                  stack =
                  parens =
                  for i, c in enumerate(my_str):
                  if c == "(":
                  stack.append(i)
                  elif c == ")":
                  parens.append((stack.pop(), i))
                  print(parens) # [(18, 19), (8, 20), (4, 24), (31, 33)]


                  But if you value one-liners more than readability or coding conventions, you could also cram that into a list comprehensions with side effects:



                  stack = 
                  parens = [(stack.pop(), i) for i, c in enumerate(my_str)
                  if c == "(" and stack.append(i) or c == ")"]
                  print(parens) # [(18, 19), (8, 20), (4, 24), (31, 33)]


                  This uses the fact that and and or are short-circuit-evaluated, thus it will append items only if c == "(", but then fail because append return None, and only add elements to the results if the second condition, c == ")" is true, popping the position of the most recent ( from the stack.



                  At least, it is not a total abuse of list comprehensions, as the result is not discarded but actually the desired result, and it's probably still easier to comprehend than the three list comprehensions that you have (although those work without side effects), but the better solution for a "handy" way to do this would be: Make it a function, than it does not matter how many lines it has.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 15 '18 at 16:58

























                  answered Nov 15 '18 at 16:49









                  tobias_ktobias_k

                  59.1k971110




                  59.1k971110



























                      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%2f53311626%2flist-comprehension-to-find-matching-parens%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

                      Use pre created SQLite database for Android project in kotlin

                      Darth Vader #20

                      Ondo