18
\$\begingroup\$

Write a program that takes in a string where every line consists of the character 0 indented by some number of spaces. The top line is not indented and every other line will be indented by at most one more space than the line just before it.

No lines will have trailing spaces but you may optionally assume there is a single trailing newline.

For example, the input might look something like this:

0
 0
  0
  0
 0
0
 0
 0
 0
  0
0
 0
  0
  0

Your task is to number it like a hierarchical outline, using increasing positive integers as the line headers. This would be the output for the example:

1
 1
  1
  2
 2
2
 1
 2
 3
  1
3
 1
  1
  2

Note how every hierarchical indentation level has its own set of increasing numbers, even if they only go up to one.

In the output, there should be no trailing spaces, but there may optionally be a single trailing newline.

Write a full program that takes the input string via stdin or command line, or write a function that takes the string in as an argument. Print the result or return it as a string.

The shortest code in bytes wins.

Examples

If the empty string is input, the empty string should be output.

The next most trivial example is the input

0

which should become

1

Large example - Input:

0
 0
  0
 0
  0
 0
  0
  0
   0
   0
    0
     0
     0
     0
     0
    0
   0
    0
    0
  0
0
 0
  0
 0
  0
  0
  0
  0
  0
  0
  0
  0
  0
  0
  0
   0
    0
     0
  0
   0
0
0
0
 0
  0
   0
    0
     0
      0
      0
     0
    0
   0
  0
 0
  0
  0
   0
   0
0
0

Output:

1
 1
  1
 2
  1
 3
  1
  2
   1
   2
    1
     1
     2
     3
     4
    2
   3
    1
    2
  3
2
 1
  1
 2
  1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  11
   1
    1
     1
  12
   1
3
4
5
 1
  1
   1
    1
     1
      1
      2
     2
    2
   2
  2
 2
  1
  2
   1
   2
6
7
\$\endgroup\$
0

7 Answers 7

8
\$\begingroup\$

Python 2, 77

S={'0':0}
for w in input().split('\n'):S[w]+=1;S[' '+w]=0;print w[:-1]+`S[w]`

Like Sp3000's answer, but with a dictionary. The dict S stores the current number for each nesting level '0', ' 0', ' 0' and so on. For each line in the input, increment the corresponding nesting level, and reset the nesting level one higher to 0.

\$\endgroup\$
6
\$\begingroup\$

Python 2, 86 85 81 bytes

S=[]
for r in input().split("\n"):S=([0]+S)[-len(r):];S[0]+=1;print r[:-1]+`S[0]`

(-5 bytes thanks to @xnor)

Takes input as a string via STDIN, e.g.

'0\n 0\n  0\n  0\n 0\n0\n 0\n 0\n 0\n  0\n0\n 0\n  0\n  0'

Alternatively, here's a function for 5 extra bytes:

def f(I,S=[]):
 for r in I.split("\n"):S=([0]+S)[-len(r):];S[0]+=1;print r[:-1]+`S[0]`
\$\endgroup\$
3
  • \$\begingroup\$ I found that you can save some chars by taking in each line as a string of spaces so you can print those spaces directly S=[]\nfor w in input()[:-1].split('0\n'):S=([0]+S)[~len(w):];S[0]+=1;print w+`S[0]` \$\endgroup\$
    – xnor
    Commented Jul 22, 2015 at 0:12
  • \$\begingroup\$ Actually, it's a bit shorter to take in the line directly: S=[]\nfor w in input().split('\n'):S=([0]+S)[-len(w):];S[0]+=1;print w[:-1]+`S[0]` . \$\endgroup\$
    – xnor
    Commented Jul 22, 2015 at 0:16
  • \$\begingroup\$ @xnor Thanks again - that's a lot simpler :) \$\endgroup\$
    – Sp3000
    Commented Jul 22, 2015 at 0:24
4
\$\begingroup\$

CJam, 25 bytes

LqN/{0+I,<))_IW@toNo+}fI;

Like my Python answer, this uses an array to store which number each indentation level is up to. One difference, however, is that this uses t (array set) to replace the 0 on each line with the number we want.

Try it online.

\$\endgroup\$
3
\$\begingroup\$

JavaScript ES6, 83 81 bytes

f=(z,a=[])=>z.replace(/ *0/g,e=>e.replace(0,a.fill(0,l=e.length)[--l]=a[l]+1||1))

This uses an array that holds the current number for each indentation level. Everything past that level is reset to 0 using fill(). EDIT: 2 bytes saved thanks to vihan1086's tip.

The Stack Snippet below can be used for testing because it is ungolfed slightly and uses better-supported ES5 syntax. The second function is a polyfill for fill() as there is not a short way to do it without ES6.

f=function(z){
  a=[]
  return z.replace(/ *0/g,function(e){
    return e.replace(0,a.fill(0,l=e.length)[--l]=a[l]+1||1)
  })
}

if(!Array.prototype.fill){
  Array.prototype.fill = function(val, start){
    var res = this;
    for(var i = start; i<this.length; i++){
      res[i] = val;
    }
    return res;
  };
}

run=function(){document.getElementById('output').innerText=f(document.getElementById('input').value)};document.getElementById('run').onclick=run;run()
<textarea id="input" rows="15" cols="10">
0
 0
  0
  0
 0
0
 0
 0
 0
  0
0
 0
  0
  0</textarea>
<pre id="output" style="display:inline-block; vertical-align:top; margin:0"></pre><br />
<button id="run">Run</button>

\$\endgroup\$
0
2
\$\begingroup\$

Pyth, 18 bytes

V.z+PNhX0=Y>lN+0Y1

This is an exact translation of @Sp3000's answer. I tried many different approaches and variations, but I couldn't shorten it, so I am marking this CW.

Demonstration.

\$\endgroup\$
1
\$\begingroup\$

Python - 191

def p(s,i,v,n=1):
    while i<len(s)and s[i]and'0'not in s[i][:v]:
        if s[i][v]=='0':s[i]=' '*v+str(n);n+=1;i+=1
        else:i=p(s,i,v+1)
    return(s,i)[v!=0]
z=lambda r:'\n'.join(p(r.split('\n'),0,0))

The function is z.

\$\endgroup\$
0
\$\begingroup\$

Pip -rn, 31 27 bytes

{Wl#<alPU0l@>:-#aaR0++@l}Mg

Input from stdin. Try it online!

Explanation

                             g is list of lines of stdin (-r flag); l is []
                             Note that l is a global variable
{                       }Mg  Map this function to each a in g:
 Wl#<a                        While l is less in length than a:
      lPU0                     Push a 0 to (the front of) l
                              (This handles increasing the indent)
          l@>:                Slice and assign back to l...
              -#a              ... its last len(a) elements
                              (This handles decreasing the indent)
                 aR0          In a, replace 0 with
                      @l       the first element of l
                    ++         incremented in-place
                              The function returns the above expression
                             The resulting list from map is printed, newline-separated
                              (-n flag)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.