Numbering Hierarchical Outlines

18

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

Calvin's Hobbies

Posted 2015-07-21T22:19:06.310

Reputation: 84 000

Answers

2

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.

isaacg

Posted 2015-07-21T22:19:06.310

Reputation: 39 268

8

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.

xnor

Posted 2015-07-21T22:19:06.310

Reputation: 115 687

6

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]`

Sp3000

Posted 2015-07-21T22:19:06.310

Reputation: 58 729

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]` – xnor – 2015-07-22T00:12:32.770

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]`. – xnor – 2015-07-22T00:16:05.730

@xnor Thanks again - that's a lot simpler :) – Sp3000 – 2015-07-22T00:24:14.897

4

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.

Sp3000

Posted 2015-07-21T22:19:06.310

Reputation: 58 729

3

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>

NinjaBearMonkey

Posted 2015-07-21T22:19:06.310

Reputation: 9 925

1

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.

faubi

Posted 2015-07-21T22:19:06.310

Reputation: 2 599

0

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)

DLosc

Posted 2015-07-21T22:19:06.310

Reputation: 21 213