64
\$\begingroup\$

I've heard that your code can run faster if you indent it in reverse, so that the compiler can process it like a tree design pattern from the very top of the "branches" down. This helps because gravity will speed up the time it takes for your code to be compiled, and the data structure efficiency is improved. Here's an example, in Java scripting:

            function fib(n) {
        var a = 1, b = 1;
        while (--n > 0) {
    var tmp = a;
    a = b;
    b += tmp;
    if (a === Infinity) {
return "Error!";
    }
        }
        return a;
            }

But for some reason Notepad doesn't have a setting to do this automatically, so I need a program to do it for me.

Description

Submissions must take a code snippet as input, reverse the indentation, and output the resulting code.

This is done by the following procedure:

  • Split the code up into lines. Each line will start with zero or more spaces (there will be no tabs).

  • Find all unique indentation levels in the code. For example, for the above example, this would be

    0
    4
    8
    12
    
  • Reverse the order of this list of indentation levels, and map the reversed list to the original list. This is hard to explain in words, but for the example, it would look like

    0  — 12
    4  — 8
    8  — 4
    12 — 0
    
  • Apply this mapping to the original code. In the example, a line with 0-space-indentation would become indented by 12 spaces, 4 spaces would become 8 spaces, etc.

Input / Output

The input and output can be provided however you would like (STDIN/STDOUT, function parameter/return value, etc.); if your language does not support multiline input (or you just don't want to), you can use the | character to separate lines instead.

The input will consist of only printable ASCII + newlines, and it will not contain empty lines.

Test cases

Input:

function fib(n) {
    var a = 1, b = 1;
        while (--n > 0) {
            var tmp = a;
            a = b;
            b += tmp;
            if (a === Infinity) {
                return "Error!";
            }
        }
    return a;
}

Output: the example code above.

Input:

a
  b
  c
d
   e
        f
  g
   h

Output:

        a
   b
   c
        d
  e
f
   g
  h

Input:

1
 2
  3
 2
1

Output:

  1
 2
3
 2
  1

Input:

  foo

Output:

  foo
\$\endgroup\$
  • 21
    \$\begingroup\$ Its "JavaScript" not "Java scripting" :/ \$\endgroup\$ – Optimizer Dec 18 '14 at 21:36
  • 75
    \$\begingroup\$ @Optimizer I see that my goal of infuriating as many people as possible with the first two paragraphs has been achieved. ;) \$\endgroup\$ – Doorknob Dec 18 '14 at 21:42
  • 7
    \$\begingroup\$ 1 != as many people as possible. \$\endgroup\$ – Optimizer Dec 18 '14 at 21:44
  • 23
    \$\begingroup\$ @JanDvorak The same guys that invented MLA style citations think this is a good idea. \$\endgroup\$ – Rainbolt Dec 18 '14 at 21:53
  • 6
    \$\begingroup\$ Supposedly, it's faster. Let's assign a committee to it and wait a few years while we forget the purpose of it. \$\endgroup\$ – Conor O'Brien Dec 18 '14 at 23:19

12 Answers 12

10
\$\begingroup\$

CJam, 43 39 36 35 bytes

qN/_{_Sm0=#}%___&$_W%er]z{~S*@+>N}%

This looks toooo long. I am sure I am not Optimizing enough!

How it works:

Basic idea is to split the input on newline, calculate the number of leading spaces in each line, sort and get unique numbers, copy that array and reverse the copy, transliterate the original in-order numbers with this two arrays and then finally form the final string using this information.

The lengthiest part is to figure out how many leading spaces are there in each line as CJam does not have an easy way of doing it.

Code expansion:

qN/_                                      "Split the string on newline and take copy";
    {_Sm0=#}%                             "Map this code block on the copy";
     _Sm                                  "Copy the string and remove spaces from the copy";
        0=                                "Get first non space character";
          #                               "Gets its index in original string";
             ___                          "Get 3 copies of the above array";
                &$_W%                     "Get unique elements, sort, copy and reverse";
                     er                   "Transliterate unique sorted elements with";
                                          "the unique reverse sorted in the copy";
                       ]z                 "Get array of [row,
                                          " original number of leading spaces,
                                          " required number of leading spaces]";
                         {~S*@+>N}%       "For each above combination";
                          ~S*             " unwrap and get leading space string";
                             @+           " prepend to the row";
                               >          " remove original spaces";
                                N         " put newline";

And in the spirit of the question. A real expansion of the code:

                                          qN/_                                      "Split the string on newline and take copy";
                                {_Sm0=#}%                             "Map this code block on the copy";
                               _Sm                                  "Copy the string and remove spaces from the copy";
                             0=                                "Get first non space character";
                          #                               "Gets its index in original string";
                         ___                          "Get 3 copies of the above array";
                       &$_W%                     "Get unique elements, sort, copy and reverse";
                     er                   "Transliterate unique sorted elements with";
"the unique reverse sorted in the copy";
                ]z                 "Get array of [row,
" original number of leading spaces,
" required number of leading spaces]";
             {~S*@+>N}%       "For each above combination";
          ~S*             " unwrap and get leading space string";
        @+           " prepend to the row";
     >          " remove original spaces";
    N         " put newline";

7 bytes saved thanks to Martin and 1 byte thanks to Dennis

Try it online here

\$\endgroup\$
  • \$\begingroup\$ 1. {}# has a bug: it returns an Integer, but it should return a Long. Ironically, i (cast to integer) fixes this. 2. Since ""# doesn't have the same bug, _Sm0=# is one byte shorter. \$\endgroup\$ – Dennis Dec 19 '14 at 3:29
  • \$\begingroup\$ @Dennis Yeah, the bug is weird. Thanks for the workaround ! \$\endgroup\$ – Optimizer Dec 19 '14 at 7:01
  • 2
    \$\begingroup\$ this indentation in the expansion is so easy to read! You should reverse it! \$\endgroup\$ – DLeh Dec 19 '14 at 21:08
13
\$\begingroup\$

Python 2 - 137 131 bytes

i=raw_input().split('|')
f=lambda s:len(s)-len(s.lstrip())
d=sorted(set(map(f,i)))
for l in i:print' '*d[~d.index(f(l))]+l.lstrip()

Takes input with | instead of \n.

Explanation

The first three lines are fairly straightforward. Make a list of all the lines in the input, define a function that tells you how much leading whitespace a string has, and make a sorted list of values that function spits out for each line of input.

The last line is way more fun.

                                 l               # string with the line
                               f(l)              # amount of leading whitespace
                       d.index(f(l))             # where it is in list of whitespace amounts
                      ~d.index(f(l))             # bitwise NOT (~n == -(n+1))
                    d[~d.index(f(l))]            # index into the list (negative = from end)
           print' '*d[~d.index(f(l))]            # print that many spaces...
           print' '*d[~d.index(f(l))]+l.lstrip() # plus everything after leading whitespace
for l in i:print' '*d[~d.index(f(l))]+l.lstrip() # do the above for every line
\$\endgroup\$
  • \$\begingroup\$ Confirmed 137 :) \$\endgroup\$ – FryAmTheEggman Dec 18 '14 at 21:59
  • \$\begingroup\$ @frya thanks :) \$\endgroup\$ – undergroundmonorail Dec 18 '14 at 22:06
  • 1
    \$\begingroup\$ This all seems fine in python 3 which should save you 2 bytes (pay 2 for () save 4 for raw_) \$\endgroup\$ – FryAmTheEggman Dec 18 '14 at 23:08
  • 1
    \$\begingroup\$ f(s)for s in i should be map(f,i). \$\endgroup\$ – feersum Dec 18 '14 at 23:14
  • 1
    \$\begingroup\$ A piece of magic: d=[];d+=set(L) is a shorter version of d=sorted(set(L)). \$\endgroup\$ – xnor Dec 19 '14 at 6:53
7
\$\begingroup\$

JavaScript, ES6, 113 103 101 bytes

I am pretty sure this can be golfed at least a little further, but here goes.

Never would have thought that there will be a 101 bytes JS solution, beating Python!

f=a=>(b=c=[...Set(a.match(r=/^ */gm).sort())],c.map((x,i)=>b[x]=c.slice(~i)[0]),a.replace(r,x=>b[x]))

This creates a method named f which can be called with the input string. If you are in a latest Firefox, you have template strings and you can call the method like

f(`a
  b
  c
d
   e
        f
  g
   h`)

Otherwise, you can also call it like

f("a\n\
  b\n\
  c\n\
d\n\
   e\n\
        f\n\
  g\n\
   h")

or, try the snippet below:

g=_=>O.textContent=f(D.value)

f=a=>(b=c=[...Set(a.match(r=/^ */gm).sort())],c.map((x,i)=>b[x]=c.slice(~i)[0]),a.replace(r,x=>b[x]))
<textarea id=D></textarea><button id=B onclick=g()>Inverse!</button>
<pre id=O></pre>

\$\endgroup\$
  • \$\begingroup\$ You can save a coupes bytes by storing the regex as a variable, as it is used twice (you should be able to replace \s with a space character), and removing the parentheses around x in the replace function. \$\endgroup\$ – NinjaBearMonkey Dec 19 '14 at 1:57
  • \$\begingroup\$ @hsl gee, thanks! I don't even know why I wrote (x) :/ \$\endgroup\$ – Optimizer Dec 19 '14 at 7:06
  • \$\begingroup\$ You don't need both b and c do you? They just refer to the same array anyway. \$\endgroup\$ – Neil May 11 '16 at 15:00
5
\$\begingroup\$

Ruby, 63 bytes

->s{l=s.scan(r=/^ */).uniq.sort;s.gsub r,l.zip(l.reverse).to_h}

This defines an unnamed function which takes and returns a string. You can call it by appending ["string here"] or by assigning it to a variable, and then calling that variable.

How it works: s.scan(r=/^ */) gives a list of all leading spaces and stores that regex in r for later use. uniq eliminates duplicates. sort... sorts.

Now skip to the end, l.zip(l.reverse) gives an array of pairs we want to substitute. to_h turns that into a hash, interpreting the pairs as key-value pairs.

Now s.gsub replaced all matches of the regex (all leading spaces) by using that hash as a look up table to find the replacement.

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

Pyth 39

L-/bd/rb6dJcz\|KS{mydJFNJ+*d@_KxKyN>NyN

Try it online.

Uses the | delimiter option.

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

Japt -R, 27 bytes

·
mâ\S
Vâ n
Ëx2 iSpWg~WbVgE

Try it online!

Unpacked & How it works

Input: U = multiline string

qR    Split by newline and implicit assign to U

mâ\S
m     Map over U...
 â\S    .search(/\S/); first index of non-whitespace char
      Implicit assign to V (V = array of indentations)

Vâ n  Take unique elements of V, sort, and implicit assign to W

mDEF{Dx2 iSpWg~WbVgE
mDEF{                 Map over U...
     Dx2                Trim left
         iSp            Indent by this many spaces...
                 VgE      Find the current indentation stored in V
               Wb         Find its index on W
            Wg~           Take the opposite element on W

-R    Join with newline

How it really works

                 Input: U = multiline string

                 qR    Split by newline and implicit assign to U

                 mâ\S
                 m     Map over U...
               â\S    .search(/\S/); first index of non-whitespace char
         Implicit assign to V (V = array of indentations)

                 Vâ n  Take unique elements of V, sort, and implicit assign to W

                 mDEF{Dx2 iSpWg~WbVgE
                 mDEF{                 Map over U...
            Dx2                Trim left
      iSp            Indent by this many spaces...
VgE      Find the current indentation stored in V
 Wb         Find its index on W
     Wg~           Take the opposite element on W

                 -R    Join with newline
\$\endgroup\$
1
\$\begingroup\$

Scala, 176171

def g(n:String)={val a=n.split('|').map(a=>a.prefixLength(' '==)->a)
(""/:a){case(s,(l,p))=>val b=a.unzip._1.distinct.sorted
s+" "*b.reverse(b.indexOf(l))+p.drop(l)+'\n'}}

It will add an extra newline at the end. If I did not have to preserve spaces at the end of the line, I can get it to 167:

def t(n:String)={val a=n.split('|').map(a=>a.prefixLength(' '==)->a.trim)
(""/:a){(s,l)=>val b=a.unzip._1.distinct.sorted
s+" "*b.reverse(b.indexOf(l._1))+l._2+'\n'}}

Ungolfed:

      def reverseIndent(inString: String): String = {
    val lines = inString.split('\n')
    val linesByPrefixLength = lines.map { line =>
  line.prefixLength(char => char == ' ') -> line
    }
    val distinctSortedPrefixLengths = linesByPrefixLength.map(_._1).distinct.sorted
    val reversedPrefixes = distinctSortedPrefixLengths.reverse
    linesByPrefixLength.foldLeft("") { case (string, (prefixLength, line)) =>
  val newPrefixLength = reversedPrefixes(distinctSortedPrefixLengths.indexOf(prefixLength))
  val nextLinePrefix = " " * newPrefixLength
  string + nextLinePrefix + line.substring(prefixLength) + '\n'
    }
      }
\$\endgroup\$
1
\$\begingroup\$

PowerShell, 112 bytes

$x=@($args|sls '(?m)^ *'-a|% m*|% v*|sort -u)
[regex]::Replace($args,'(?m)^ *',{$x[-1-$x.IndexOf($args.Value)]})

Try it online!

Less golfed:

$xIdents=@($args|select-string '(?m)^ *'-AllMatches|% matches|% value|sort -unique) # get a sorted set of indentations
[regex]::Replace($args,'(?m)^ *',{$xIdents[-1-$xIdents.IndexOf($args.Value)]})    # replace each indentation with opposite one
\$\endgroup\$
0
\$\begingroup\$

Haskell, 116

import Data.List
f s|l<-map(span(==' '))$lines s=unlines[k++b|(a,b)<-l,(k,r)<-reverse>>=zip$sort$nub$map fst l,r==a]
\$\endgroup\$
0
\$\begingroup\$

PHP - 173 bytes

The unoptimized code should be stored in the $v variable:

<?php $f='preg_replace';$f($p='#^ *#me','$i[]='.$s='strlen("$0")',$v);$a=$b=array_unique($i);sort($a);rsort($b);echo$f($p,'str_repeat(" ",array_combine($a,$b)['.$s.'])',$v);

Here is the ungolfed and commented version:

<?php
// Get the level of indentation for each line
$preg_replace = 'preg_replace';
$pattern = '#^ *#me';
$strlen = 'strlen("$0")';
$preg_replace($pattern, '$indentationLevelsOldList[] = '. $strlen, $value);

// Create an array associating the old level of indentation with the new expected one
$sortedArray = array_unique($indentationLevelsOldList);
$reverseSortedArray = $sortedArray;

sort($sortedArray);
rsort($reverseSortedArray);

$indentationLevelsNewList = array_combine($sortedArray, $reverseSortedArray);

// Print the correctly indented code
echo $preg_replace($pattern, 'str_repeat(" ", $indentationLevelsNewList['. $strlen .'])', $value);

I've probably never written something so dirty. I'm ashamed.

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

JavaScript, 351

var i=0;var a=$("#i").html().split("\n");var b=[];for(;i<a.length;i++){j=a[i].match(/\s*/)[0];if(b.indexOf(j)<0){b.push(j);}}b.sort(function(a,b){return a - b;});var c=b.slice().reverse();var d="";for(i=0;i<a.length;i++){d+=a[i].replace(/\s*/,c[b.indexOf(a[i].match(/\s*/)[0])])+"\n";j=a[i].search(/\S/);if(b.indexOf(j)<0){b.push(j);}}$("#i").html(d);

Ungolfed version:

var i = 0;
var a = $("#i").html().split("\n");
var b = [];
for (; i < a.length; i++) {
  j = a[i].match(/\s*/)[0];
  if (b.indexOf(j) < 0) {
    b.push(j);
  }
}
b.sort(function(a, b) {
  return a - b;
});
var c = b.slice().reverse();
var d = "";
for (i = 0; i < a.length; i++) {
  d += a[i].replace(/\s*/, c[b.indexOf(a[i].match(/\s*/)[0])]) + "\n";
  j = a[i].search(/\S/);
  if (b.indexOf(j) < 0) {
    b.push(j);
  }
}
$("#i").html(d);

Testing

var i=0;var a=$("#i").html().split("\n");var b=[];for(;i<a.length;i++){j=a[i].match(/\s*/)[0];if(b.indexOf(j)<0){b.push(j);}}b.sort(function(a,b){return a - b;});var c=b.slice().reverse();var d="";for(i=0;i<a.length;i++){d+=a[i].replace(/\s*/,c[b.indexOf(a[i].match(/\s*/)[0])])+"\n";j=a[i].search(/\S/);if(b.indexOf(j)<0){b.push(j);}}$("#i").html(d);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre><code id="i">
function fib(n) {
    var a = 1, b = 1;
        while (--n > 0) {
            var tmp = a;
            a = b;
            b += tmp;
            if (a === Infinity) {
                return "Error!";
            }
        }
    return a;
}
</code></pre>

var i=0;var a=$("#i").html().split("\n");var b=[];for(;i<a.length;i++){j=a[i].match(/\s*/)[0];if(b.indexOf(j)<0){b.push(j);}}b.sort(function(a,b){return a - b;});var c=b.slice().reverse();var d="";for(i=0;i<a.length;i++){d+=a[i].replace(/\s*/,c[b.indexOf(a[i].match(/\s*/)[0])])+"\n";j=a[i].search(/\S/);if(b.indexOf(j)<0){b.push(j);}}$("#i").html(d);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre><code id="i">
a
  b
  c
d
   e
        f
  g
   h
</code></pre>

var i=0;var a=$("#i").html().split("\n");var b=[];for(;i<a.length;i++){j=a[i].match(/\s*/)[0];if(b.indexOf(j)<0){b.push(j);}}b.sort(function(a,b){return a - b;});var c=b.slice().reverse();var d="";for(i=0;i<a.length;i++){d+=a[i].replace(/\s*/,c[b.indexOf(a[i].match(/\s*/)[0])])+"\n";j=a[i].search(/\S/);if(b.indexOf(j)<0){b.push(j);}}$("#i").html(d);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre><code id="i">
1
 2
  3
 2
1
</code></pre>

var i=0;var a=$("#i").html().split("\n");var b=[];for(;i<a.length;i++){j=a[i].match(/\s*/)[0];if(b.indexOf(j)<0){b.push(j);}}b.sort(function(a,b){return a - b;});var c=b.slice().reverse();var d="";for(i=0;i<a.length;i++){d+=a[i].replace(/\s*/,c[b.indexOf(a[i].match(/\s*/)[0])])+"\n";j=a[i].search(/\S/);if(b.indexOf(j)<0){b.push(j);}}$("#i").html(d);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre><code id="i">
  foo
</code></pre>

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

Perl 5, 112

111 + 1 for -n (-E is free)

@{$.[$.]}=/( *)(.*)/;++$_{$1}}{map$_{$_[$#_-$_]}=$_[$_],0..(@_=sort keys%_);say$_{$.[$_][0]}.$.[$_][1]for 0..$.

I'm sure it can be done in fewer strokes, but I don't see how at the moment.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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