Golf A Parentheses Matching Algorithm

25

1

You will be given a string s. It is guaranteed that the string has equal and at least one [s and ]s. It is also guaranteed that the brackets are balanced. The string can also have other characters.

The objective is to output/return a list of tuples or a list of lists containing indices of each [ and ] pair.

note: The string is zero-indexed.

Example: !^45sdfd[hello world[[djfut]%%357]sr[jf]s][srtdg][] should return

[(8, 41), (20, 33), (21, 27), (36, 39), (42, 48), (49, 50)] or something equivalent to this. Tuples are not necessary. Lists can also be used.

Test cases:

input:[[asdf][][td([)ty54g% ]hg[[f]u][f[[jhg][gfd]sdf]sdfs]ghd]fr43f]
output:[(0, 62),(1, 6), (7, 8), (9, 56), (13, 22), (25, 30), (26, 28), (31, 52), (33, 47), (34, 38), (39, 43)]
input:[[][][][]][[][][][[[[(]]]]]))
output:[(0, 9), (1, 2), (3, 4), (5, 6), (7, 8), (10,26),(11, 12), (13, 14), (15, 16), (17, 25), (18, 24), (19, 23), (20, 22)]
input:[][][[]]
output:[(0, 1), (2, 3), (4, 7), (5, 6)]
input:[[[[[asd]as]sd]df]fgf][][]
output:[(0, 21), (1, 17), (2, 14), (3, 11), (4, 8), (22, 23), (24, 25)]
input:[]
output:[(0,1)]
input:[[(])]
output:[(0, 5), (1, 3)]

This is , so the shortest code in bytes for each programming language wins.

Windmill Cookies

Posted 2018-06-07T16:44:33.260

Reputation: 601

Related – JungHwan Min – 2018-06-07T17:03:22.893

1Does the output order matter? – wastl – 2018-06-07T17:04:57.347

1no, it does not. – Windmill Cookies – 2018-06-07T17:05:11.937

21"note: The string is zero-indexed." - It's very common to allow implementations to choose a consistent indexing in these kind of challenges (but it is, of course, up to you) – Jonathan Allan – 2018-06-07T17:05:33.910

Is there any restriction on the order of the tuple in the output? Must they be sorted in increasing open paren position? – user202729 – 2018-06-07T17:14:56.103

@user202729 no there is no restriction about the order. – Windmill Cookies – 2018-06-07T17:21:44.427

1Can we take input as an array of characters? – Shaggy – 2018-06-07T17:31:44.327

Related: Telescopic Parentheses

– Luis Mendo – 2018-06-07T17:32:06.627

@LuisMendo I think the challenge of garbage inbetween the parens makes this unique enough that I definitely can't reuse the 05AB1E implementation. – Magic Octopus Urn – 2018-06-07T17:40:54.347

@ngn thanks, will edit – Windmill Cookies – 2018-06-07T17:57:48.903

@ngn update: edited. now there is one extra closed bracket at index 26 and the string is valid. – Windmill Cookies – 2018-06-07T18:07:45.320

Can the output format be [0, 5, 1, 3] instead of [[0, 5], [1, 3]] (for example) – dylnan – 2018-06-07T18:08:52.063

@dylnan yes, but only prefer that if your language does not support nested lists. – Windmill Cookies – 2018-06-07T18:10:12.567

The language I'm thinking of does support nested lists, but it is one indexed. Can one indexed languages use one indexing? – dylnan – 2018-06-07T18:18:05.447

1why not just subtract 1 from every index? – Windmill Cookies – 2018-06-07T18:18:59.570

7Costs one byte... – dylnan – 2018-06-07T18:28:16.353

More in some languages. – Shaggy – 2018-06-08T09:25:01.090

Answers

13

Brain-Flak Classic, 108 bytes

{((((((([][][]){}){}){}()){}){}{}[])()()){{}<>{}(<>)}{}((){[](<{}>)}{}){{}<>[({}<[{}]>)](<>)}{}<>(({}()))<>}

Try it online!

Stores each opening [ in the right stack, and outputs whenever we hit a ].

Nitrodon

Posted 2018-06-07T16:44:33.260

Reputation: 9 181

12

Python 2, 74 bytes

s=[];i=0
for c in input():
 if'['==c:s+=i,
 if']'==c:print s.pop(),i
 i+=1

Try it online!

Rod

Posted 2018-06-07T16:44:33.260

Reputation: 17 588

5

JavaScript, 69 62 bytes

A quick bit of golf on the train home. Can probably be improved on.

Takes input as an array of characters and outputs an object with the keys being the indices of the [s and their values being the indices of their corresponding ]s.

a=>a.map((x,y)=>x==`]`?o[a.pop()]=y:x==`[`&&a.push(y),o={})&&o

Try it online

Shaggy

Posted 2018-06-07T16:44:33.260

Reputation: 24 623

It blows my mind that you can golf on mobile. :P – Oliver – 2018-06-07T18:09:21.733

2@Oliver, it blows my mind that I can (just about) type on touchscreens at all - bring back keyboards! – Shaggy – 2018-06-07T18:36:15.847

4

Haskell, 92 79 bytes

g(u:a)n(']':x)=(u,n):g a(n+1)x
g a n(s:x)=g([n|s=='[']++a)(n+1)x
g[]_[]=[]
g[]0

Try it online!

Explanation

We create a function g which takes 3 arguments.

  • a, which is the locations of all unmatched [s.

  • n, which is the number of characters processed

  • x which is the characters unprocessed.

If our first character is ] we remove u from the front our a and return (u,n) plus whatever else remains.

g(u:a)n(']':x)=(u,n):g a(n+1)x

If our first character is not ], that is either [ or something else, we increment n and add [n|s=='['] to the front of a. [n|s=='['] will be [n] if s=='[' and [] otherwise.

g a n(s:x)=g([n|s=='[']++a)(n+1)x

If we are out of characters we return the empty list.

g[]_[]=[]

Post Rock Garf Hunter

Posted 2018-06-07T16:44:33.260

Reputation: 55 382

1wow, thats some nice piece of recursive functions. I'm a beginner on Haskell, this impressed me:) – Windmill Cookies – 2018-06-07T17:01:48.487

@gnu-nobody Thanks! This answer is probably not optimal, so I would encourage you to try and beat it, or wait until the serious Haskell golfers arrive. – Post Rock Garf Hunter – 2018-06-07T17:08:33.933

I'd better wait until the serious Haskell golfers arrive – Windmill Cookies – 2018-06-07T17:09:55.860

4

QBasic (QB64), 137 127 112 bytes

INPUT a$
for i=0to len(a$)
c$=mid$(a$,i+1,1)
if"["=c$then
b(n)=i
n=n+1
elseif"]"=c$then
n=n-1
?b(n),i
endif
next

We need four two bytes because the challenge requires 0-indexing. My first QBasic post, feedback is appreciated.

  • 10 bytes thanks to steenbergh
  • 3 bytes thanks to Erik the Outgolfer
  • 12 bytes by saving in unix file format (\r\n -> \n)

Looks like this when executed:

How it looks

wastl

Posted 2018-06-07T16:44:33.260

Reputation: 3 089

Nice one. Couple of pointers: use ? instead of print (the compiler auto-expands this to print), you don't need the spaces between the quoted strings and THEN in the IFs, and you can drop the i after NEXT. – steenbergh – 2018-06-07T18:25:23.133

@steenbergh Huh, seems I forgot to remove whitespace ... but I removed the one between 0 and to? I'm confused ... – wastl – 2018-06-07T19:06:31.790

1Not sure about QB64, but I think if c$="[" can become if"["=c$, elseif c$="]" can become elseif"]"=c$, end if can become endif, and, with a slight change in the output, ?b(n),i can become ?b(n)i (QBasic 1.1 is what I use, your case might be different). – Erik the Outgolfer – 2018-06-08T11:42:01.913

@EriktheOutgolfer all but ?b(n)i worked – wastl – 2018-06-08T12:11:53.823

4

Java 10, 95 bytes

A void lambda taking the input string as an int[] of Unicode code points.

s->{int r=0,w=0;for(var c:s){if(c==91)s[w++]=r;if(c==93)System.out.println(s[--w]+","+r);r++;}}

Try It Online

Ungolfed

s -> {
    int r = 0, w = 0;
    for (var c : s) {
        if (c == 91)
            s[w++] = r;
        if (c == 93)
            System.out.println(s[--w] + "," + r);
        r++;
    }
}

Acknowledgments

  • thanks to Jonathan Frech for the idea of using the input string as a stack (here)

Jakob

Posted 2018-06-07T16:44:33.260

Reputation: 2 428

You must define r and w as part of the code, not as parameters: s->{int r=0,w=0;...}. – Olivier Grégoire – 2018-06-07T21:10:20.767

@OlivierGrégoire Kind of ambiguous, but this looks like it was intended to cover multiple empty inputs.

– Jakob – 2018-06-07T21:19:08.247

1The answer you quote explicitly answers the question "Are we allowed to take an empty parameter instead we won't use anywhere?". You're using these inputs. I see no ambiguity at all here. – Olivier Grégoire – 2018-06-07T21:20:52.883

The edit part of the question makes it absolutely unambiguous about the "no-use" the variable. – Olivier Grégoire – 2018-06-07T21:30:48.833

Right, but then why does the top answer (1) not state that inputs are unused, (2) specify what the values of extra inputs are, and (3) mention the possibility of abusing extra inputs? Regardless, I'll move the variables. – Jakob – 2018-06-07T21:43:09.213

Because 1. the context of the answer is clearly the question which unequivocally says "unused parameters", 2. to make sure we can identify unused parameters from the method call (also, Nathan Merill always wanted to make things very defined, even when unneeded, which is the case here), 3. if it's shorter to declare an extra input but not using it, you may define it. That's basically what Nathan Merill said in his answer. – Olivier Grégoire – 2018-06-07T21:57:02.583

4

vim, 89 bytes

:s/\(.\)/\1<C-V><C-M>/g|g/^\[/ :norm %mm%:pu! =line('.').','.line(\"'m\")<C-V><C-M><C-X>$<C-X>J
:v/\[/d|%s/\[//g

Annotated

:s/\(.\)/\1<C-V><C-M>/g            " one character per line
|g/^\[/                            " for each opening square bracket:
  :norm %mm%                       "   mark the line with the matching bracket
  :pu! =line('.').','.line(\"'m\") "   write the line numbers to preceeding line
  <C-V><C-M><C-X>$<C-X>J           "   convert to 0-based counting and join lines
:v/\[/d                            " remove all non-opening bracket lines
|%s/\[//g                          " remove brackets

<C-V> is 0x16. <C-M> is 0x0d. <C-X> is 0x18.

Try it online!

Ray

Posted 2018-06-07T16:44:33.260

Reputation: 1 488

3

Pyth, 26 bytes

VQIqN\[=+YZ)IqN\],.)YZ)=hZ

Try it here

Explanation

VQIqN\[=+YZ)IqN\],.)YZ)=hZ
VQ                     =hZ   For each character in the input (indexed by Z)...
  IqN\[=+YZ)                 ... if the character is [, add the index to Y...
            IqN\],.)YZ)      ... if the character is ], output the previous index
                             and current index.

user48543

Posted 2018-06-07T16:44:33.260

Reputation:

Nice! My naïve approach was 36 bytes, C,x"[" MQ #.e*qb\[t+lhfSI/LT"[]"._>Q. Edit: I succeeded golfing mine quite a bit too, I'm now below 30. – Mr. Xcoder – 2018-06-07T17:17:26.680

3

R, 141 133 115 112 108 bytes

function(y,x=utf8ToInt(y)){for(i in seq(x)){if(x[i]==91)F=c(i,F);if(x[i]==93){T=c(T,F[1],i);F=F[-1]}};T[-1]}

Try it online!

Nothing special. 1-indexed, because I said so. R doesn't really have stacks, so I originally used c, head, and tail to get the same literal effect. Ungolfed original version (updates using utf8ToInt to remove some bytes, using the start of the vector as the top of the stack, and abusing T and F builtins to avoid initializing the stacks.):

f <- function(y, x=el(strsplit(y,""))) {
  p <- l <- NULL
  for(i in seq_along(x)) {
    if(x[[i]]=='[') {
      p <- c(p, i)
    }
    if(x[[i]]==']') {
      l <- c(l, tail(p, 1), i)
      p <- head(p, -1)
    }
  }
  l # Because I said so. Change to l-1 if you want to check the test cases.
}

ngm

Posted 2018-06-07T16:44:33.260

Reputation: 3 974

Save some bytes by abusing built-ins T`` andF` – JayCe – 2018-06-08T19:21:08.497

and 1:nchar(y) is shorter than seq_along(x). Very nice solution btw :) – JayCe – 2018-06-08T19:23:17.083

I wonder if gregexpr is the way to go. – ngm – 2018-06-08T19:53:41.260

I had originally tried to leverage this approach but I am not sure if this is the right way here.

– JayCe – 2018-06-09T13:32:59.397

JayCe solution is flawed (check the result, it returns 22 28 22 instead of 22 28 21) probably the (ab)use of T/F is not really safe :D. This is shorter and seems to work --> Try it online!

– digEmAll – 2018-06-09T13:53:41.230

@digEmAll better and shorter than my nonsense! – JayCe – 2018-06-11T04:09:03.897

you can use seq(x) instead of 1:nchar(y) since y is guaranteed to have at least 2 characters. – Giuseppe – 2018-06-11T13:58:40.130

-1 byte – JayCe – 2018-06-11T19:57:48.073

2

Jelly,  22 21 20  19 bytes

No doubt it is possible in Jelly in half this byte count :p ...

n€Ø[ḅ-µMịÄÐƤi€0ĖƊ’Ä

A monadic link accepting a list of characters which returns a list of lists of integers.
As a full program it accepts a string and prints a representation of said list.

Try it online!

How?

n€Ø[ḅ-µMịÄÐƤi€0ĖƊ’Ä - Link: list of characters    e.g. "[f[o]o!]"
  Ø[                - list of characters = ['[', ']']
n€                  - not equal? for €ach              [[0,1],[1,1],[0,1],[1,1],[1,0],[1,1],[1,1],[1,0]]
                    -     ...relating to the characters:  [     f     [     o     ]     o     !     ]
    ḅ-              - convert from base -1             [1,0,1,0,-1,0,0,-1]
                    -     ...i.e.: 1 where '['; -1 where ']'; and 0 elsewhere
      µ             - start a new monadic chain with that as the argument, say V
                Ɗ   - last 3 links as a monad (function of V):
          ÐƤ        -   for post-fixes:
         Ä          -     cumulative sum               [[1,1,2,2,1,1,1,0],[0,1,1,0,0,0,-1],[1,1,0,0,0,-1],[0,-1,-1,-1,-2],[-1,-1,-1,-2],[0,0,-1],[0,-1],-1]
            i€0     -   1st index of 0 in €ach (or 0)  [8,1,3,1,0,1,1,0]
               Ė    -   enumerate                      [[1,8],[2,1],[3,3],[4,1],[5,0],[6,1],[7,1],[8,0]]
       M            - maximal indices of V             [1,3]
        ị           - index into                       [[1,8],[3,3]]
                 ’  - decrement                        [[0,7],[2,2]]
                  Ä - cumulative sum (vectorises)      [[0,7],[2,4]]

Jonathan Allan

Posted 2018-06-07T16:44:33.260

Reputation: 67 804

I was trying to use œ¿ and it's relatives but couldn't find a solution. This was closest I got.

– dylnan – 2018-06-07T19:47:30.690

Yes, it can be shorter, but I only managed one measly byte, not half the bytes. It still feels too long. :(

– Erik the Outgolfer – 2018-06-07T20:04:47.360

@EriktheOutgolfer there was an easy 1-byte save here too – Jonathan Allan – 2018-06-07T20:45:33.957

2

Forth (gforth), 75 bytes

: f 0 do dup i + c@ dup 91 = if i s>f then 93 = if f>s . i . cr then loop ;

Try it online!

Abuses the floating-point stack, but allows using a do loop since the code doesn't (manually) touch the return stack.

Explanation

  1. Loop through characters in string
  2. Check each character
    1. If equal to [, put on floating point stack
    2. if equal to ] pop from floating point stack and output with current position

Code Explanation

0 do                 \ start a loop from 0 to string-length
  dup                \ duplicate the starting address to avoid losing it
  i + c@             \ get the address of the current position and retrieve the character
  dup                \ duplicate the character, to allow checking twice
  91 = if            \ if char = [
    i s>f            \ store the current address on the floating point stack
  then               \ end the if-statement
  93 = if            \ if char = ]
    f>s .            \ pop the starting position from the float-stack and print
    i .              \ print the current position
    cr               \ output a newline
  then               \ end the if-statement
loop                 \ end the loop

reffu

Posted 2018-06-07T16:44:33.260

Reputation: 1 361

2

Retina, 36 bytes

L$v`\[((\[)|(?<-2>])|[^]])*
$.`,$.>`

Try it online! Explanation:

L

Generate a list from the match results.

$

Use the following substitution to generate the list instead of the matches.

v`

Allow matches to overlap.

\[((\[)|(?<-2>])|[^]])*

This is an application of .NET's balancing groups. The [ is matched literally, then as many characters as possible are consumed. As each subsequent [ is matched, the match is added to the $2 stack. If that stack isn't empty, we can then match a ], removing the match from the stack. Otherwise, we can match anything that's not a ] (the [ was already matched earlier). The match stops when it meets the matching ] for the [, since the $2 stack is (now) empty at that point.

$.`,$.>`

The substiution consists of two variables separated by a comma. The . indicates that the length of the variable, rather than its value, be used. The > indicates that the variable should be evaluated in terms of the right-hand separator rather than the match. The $` variable refers to the prefix of the match, which means $.` gives the position of the [; the > modifier alters this to the prefix of the match's right separator, which gives the position of the matching ].

Neil

Posted 2018-06-07T16:44:33.260

Reputation: 95 035

2

SWI-Prolog 254 bytes

d([']'|T],I,[S|Z],M,R):-J is I+1,d(T,J,Z,[',','(',S,',',I,')'|M],R).
d(['['|T],I,S,M,R):-J is I+1,d(T,J,[I|S],M,R).
d([_|T],I,S,M,R):-J is I+1,d(T,J,S,M,R).
d(_,_,_,R,R).
m(X):-atom_chars(X,A),d(A,0,[],[']'],[_|R]),atomic_list_concat(['['|R],S),print(S).

Example:

?- m('!^45sdfd[hello world[[djfut]%%357]sr[jf]s][srtdg][]').
'[(49,50),(42,48),(8,41),(36,39),(20,33),(21,27)]'
true 

Jan Drozen

Posted 2018-06-07T16:44:33.260

Reputation: 491

1

K (ngn/k), 38 37 bytes

{b@0N 2#,/=(|':+\-/a)b:&|/a:"[]"=\:x}

Try it online!

{ } function with argument x

"[]"=\:x two boolean lists for the occurrences of "[" and "]"

a: assign to a

|/ boolean "or" of the two lists

& where (at which indices) are the brackets?

b: assign to b

-/ a list with 1 for "[", -1 for "]", and 0 everywhere else

+\ partial sums

|': pairwise maxima (each element max'ed with the previous one, the initial element remains the same)

This represents bracket depth for each character. We index it with b (juxtaposition is indexing) and get bracket depth only for the brackets.

= "group by" - a dictionary mapping depths to the indices at which they occur

,/ concatenate the values in the dictionary, ignoring the keys

0N 2# reshape to a 2-column matrix (list of lists)

b@ index b with each element of the matrix

ngn

Posted 2018-06-07T16:44:33.260

Reputation: 11 449

1

C (gcc), 87 bytes

f(char*Z){for(char*z=Z,*q=z;*z;*z++-93||printf("%d,%d;",*--q,z-1-Z))*z-91||(*q++=z-Z);}

Try it online!

Explanation

To keep track of opening bracket's string indices, the input string is overwritten and used as a stack.

f(char*Z){          // take mutable input string
 for(char*z=Z,*q=z; // copy pointer to current string index, current stack index
 *z;                // loop through the entire string
 *z++-93||          // if z == ']'
   printf("%d,%d;", // decrement stack pointer,
    *--q,z-1-Z))    //  write bracket pair position
  *z-91||           // if z == '['
   (*q++=z-Z);}     // write bracket position onto stack, increment stack pointer

Try it online!

Jonathan Frech

Posted 2018-06-07T16:44:33.260

Reputation: 6 681

1

Jelly, 20 bytes

=©ⱮØ[_/aÄ$+®ŻĠḊẎ_2s2

Try it online!

It has a side-effect on the register, hope it's allowed to be a function.

Erik the Outgolfer

Posted 2018-06-07T16:44:33.260

Reputation: 38 134

It's reusable, so I think it's fine. BF answers don't typically leave the tape blank – dylnan – 2018-06-07T20:48:35.393

1

Japt v1.4.5, 23 bytes

;Ë¥']?ApENo):D¥'[©NpE
A

Try it online!

Unpacked & How it works

;UmDE{D==']?ApENo):D=='[&&NpE
A

;                              Use alternative set of initial variables
                               A = [] is used here
 UmDE{                         Map over each char of input string...
      D==']?                     If the char is closing bracket...
            ApENo)                 Push the current index and N.pop() to A
                  :D=='[&&       Otherwise, if the char is opening bracket...
                          NpE      Push the current index to N

A     Output A

The output is a flattened array of [closing index, opening index]. If the reversed order is not desired, adding w at the end does the job (+1 bytes).

Bubbler

Posted 2018-06-07T16:44:33.260

Reputation: 16 616

1

Common Lisp, 95 bytes

(lambda(u &aux s)(dotimes(p(length u))(case(elt u p)(#\[(push p s))(#\](print`(,(pop s),p))))))
Long version
(defun par (string &aux stack)
  (dotimes (pos (length string))
    (case (char string pos)
      (#\[ (push pos stack))
      (#\] (print (list (pop stack) pos))))))
Tests
((lambda(u &aux s)(dotimes(p(length u))(case(elt u p)(#\[(push p s))(#\](print`(,(pop s),p))))))
 "!^45sdfd[hello world[[djfut]%%357]sr[jf]s][srtdg][] ")

prints:

(21 27) 
(20 33) 
(36 39) 
(8 41) 
(42 48) 
(49 50)

coredump

Posted 2018-06-07T16:44:33.260

Reputation: 6 292

1

CJam, 25 bytes

0q{"[]"#"_ \p_p "S/=~)}/;

Surprisingly competitive - loses only to Japt and Jelly [Edit: and Charcoal and Stax :(]

Try it online!

Explanation

0                          Push 0.
 q                         Push the input.
  {                   }/   For each character in the input:
   "[]"#                     Find index of this character in the string "[]" (or -1 if not found).
                   =         Use this index to choose
        "       "S/            one of the following snippets
                    ~          and execute it:
         _                       If it was 0 ('['), duplicate the number on the stack.
           \p_p                  If it was 1 (']'), print the current number and the one under it.
                                 If it was -1, do nothing.
                     )       Increment the number on top of the stack.
                        ;  Delete the number.

Esolanging Fruit

Posted 2018-06-07T16:44:33.260

Reputation: 13 542

1

Jelly, 20 18 bytes

Saved 1 byte thanks to @user202729 informing me that µ€ is )

ẹⱮØ[µ³ḣċþØ[_/Ụị)Z’

Try it online!

After wrestling with this for several hours just to get it working... I'm honestly surprised that it's gotten this short :-)

Explanation

ẹⱮØ[µ³ḣċþØ[_/Ụị)Z’   Main link. Argument: s (string)  '[a[b]c[]][d]'
  Ø[                 Shortcut for the string "[]".
 Ɱ                   For each char in the "[]":
ẹ                      Find the indices of each occurrence in the input.
                     For our example, this gives the array [[1, 3, 7, 10], [5, 8, 9, 12]].

    µ                Begin a new monadic chain, with said array as its argument.
               )     For each of the two sub-arrays q within the array:
                         [[1, 3, 7, 10], [5, 8, 9, 12]]
     ³ḣ                For each item n in q, take the first n chars of the input.
                         [['[',     '[a[',      '[a[b]c[',   '[a[b]c[]]['],
                          ['[a[b]', '[a[b]c[]', '[a[b]c[]]', '[a[b]c[]][d]']]
        þØ[            For each string s in this, and each char c in "[]":
       ċ                 Count the occurrences of c in s.
                         [[[1, 0],  [2, 0],     [3, 1],      [4, 3]],
                          [[2, 1],  [3, 2],     [3, 3],      [4, 4]]]
           _/          Reduce each pair by subtraction. This is the number of open brackets
                         at each position.
                         [[1, 2, 2, 1], [1, 1, 0, 0]]
             U         Sort the indices by their values, using position as a tiebreaker.
                         [[1, 4, 2, 3], [3, 4, 1, 2]]
              ị        Index these values back into q.
                         [[1, 10, 3, 7], [9, 12, 5, 8]]

               )     Start a new monadic chain with the result as its argument.
                Z    Zip; transpose rows and columns.
                         [[1, 9], [10, 12], [3, 5], [7, 8]]
                 ’   Decrement; switch to 0-indexing.
                         [[0, 8], [9, 11], [2, 4], [6, 7]]

ETHproductions

Posted 2018-06-07T16:44:33.260

Reputation: 47 880

0

Python 2, 109 bytes

def a(s,r=[],i=0):
 o=[]
 while i<len(s):exec["r+=[i]","o+=[(r.pop(),i)]",'']['[]'.find(s[i])];i+=1
 return o

Try it online!

wastl

Posted 2018-06-07T16:44:33.260

Reputation: 3 089

This works as well! – Zacharý – 2018-06-07T23:25:30.170

0

Pyth,  28  26 bytes

{I#.e,t+lhfSI/LT`Y+._>Qk\]

Test suite.

At the moment it's longer than Mnemonic's approach, but I feel like I can golf this down a little and this fortunately also doesn't use Pythonically-imperative structures like V. The initial version was 36 bytes and also had numerous bugs.

How it works

{I#.e,t+lhfSI/LT`Y+._>Qk\] – Full program. Takes a quoted string Q from STDIN.
   .e                      – Enumerated map. k = iteration index, b = current element.
                     >Qk   – Get the elements of Q at indices greater than k.
                   ._      – Generates all the prefixes of this.
                  +     \] – And append an "]" (for handling some edge-cases).
          f                – Filter over this list, with T = current element.
              L `Y             – For each character in str([]), "[]"...
             / T               – ... Count the occurrences of it in T.
           SI                  – And check if the values are sorted increasingly.
         h                 – Head. Retrieve the first element.
       +l                  – Get the length of this + k.
      t                    – Decrement (by 1).
     ,                     – And pair this value with k. Returns [i, k] where i is 
                             the index of the corresponding ] and k is that of [.
  #                        – Filter this list by:
{I                             – The pair is invariant over deduplicating.

Mr. Xcoder

Posted 2018-06-07T16:44:33.260

Reputation: 39 774

{I#.e,t+lhfSI/LT`Y._>Q aaalmost works for 22 bytes... – Mr. Xcoder – 2018-06-07T17:45:55.033

0

Perl 5, 53 bytes

say"$-[0] ".($+[0]-1)while s/\[[^][]*\]/1x length$&/e

Run as perl -nE '<above code snippet>'. Takes input through stdin.

As usual, the optimal Perl solution to the problem is a regular expression. We attempt to match any pair of brackets which does not contain any pairs within it using a rather silly-looking character class (s/\[[^][]*\]/.../). If the match is successful, we replace the matched text with the digit 1 over and over again so that we don't accidentally match those brackets again, and we print out the indices of the match. Rinse and repeat.

Silvio Mayolo

Posted 2018-06-07T16:44:33.260

Reputation: 1 817

0

Stax, 13 bytes

é√p(l▓1½\á²ë(

Run and debug it

It uses the input stack to track open brace pairs. Here's the program unpacked, ungolfed, and commented.

F       iterate over input characters
 .][I   get the index of the character in the string "[]", or -1
 ^|cv   skip the rest of this iteration if index was -1
 i~     push the current iteration index to the input stack
 C      skip the rest of this iteration if index was 0
 \      form a pair with the top two items from the input stack
 JP     join with space, and print

Run this one

recursive

Posted 2018-06-07T16:44:33.260

Reputation: 8 616

0

Charcoal, 20 bytes

FLθ≡§θι[⊞υι]«I⊟υ,Iι⸿

Try it online! Link is to verbose version of code. Explanation:

FLθ

Loop over the implicit range of the length of the input string.

≡§θι

Switch on the current character.

[⊞υι

If it's a [ then push the current index to the predefined array variable.

]«I⊟υ,Iι⸿

If it's a ] then pop the latest index from the array variable and print it and the current index separated by a comma and start a new line. Alternate output formats, if acceptable, would save some bytes: ]I⟦⊟υιω saves 2 bytes but prints each index on a separate line, double-spacing the pairs of indexes; ]I⟦⊟υι simply prints the indexes on separate lines, making it hard to distinguish them.

Neil

Posted 2018-06-07T16:44:33.260

Reputation: 95 035