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 12Reverse 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 — 0Apply 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
-
24\$\begingroup\$ Its "JavaScript" not "Java scripting" :/ \$\endgroup\$Optimizer– Optimizer2014年12月18日 21:36:59 +00:00Commented Dec 18, 2014 at 21:36
-
87\$\begingroup\$ @Optimizer I see that my goal of infuriating as many people as possible with the first two paragraphs has been achieved. ;) \$\endgroup\$Doorknob– Doorknob2014年12月18日 21:42:13 +00:00Commented Dec 18, 2014 at 21:42
-
8\$\begingroup\$ 1 != as many people as possible. \$\endgroup\$Optimizer– Optimizer2014年12月18日 21:44:50 +00:00Commented Dec 18, 2014 at 21:44
-
23\$\begingroup\$ @JanDvorak The same guys that invented MLA style citations think this is a good idea. \$\endgroup\$Rainbolt– Rainbolt2014年12月18日 21:53:33 +00:00Commented Dec 18, 2014 at 21:53
-
8\$\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– Conor O'Brien2014年12月18日 23:19:16 +00:00Commented Dec 18, 2014 at 23:19
12 Answers 12
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
-
\$\begingroup\$ Confirmed 137 :) \$\endgroup\$FryAmTheEggman– FryAmTheEggman2014年12月18日 21:59:27 +00:00Commented Dec 18, 2014 at 21:59
-
1\$\begingroup\$ This all seems fine in python 3 which should save you 2 bytes (pay 2 for
()save 4 forraw_) \$\endgroup\$FryAmTheEggman– FryAmTheEggman2014年12月18日 23:08:32 +00:00Commented Dec 18, 2014 at 23:08 -
1\$\begingroup\$
f(s)for s in ishould bemap(f,i). \$\endgroup\$feersum– feersum2014年12月18日 23:14:19 +00:00Commented Dec 18, 2014 at 23:14 -
1\$\begingroup\$ A piece of magic:
d=[];d+=set(L)is a shorter version ofd=sorted(set(L)). \$\endgroup\$xnor– xnor2014年12月19日 06:53:05 +00:00Commented Dec 19, 2014 at 6:53 -
\$\begingroup\$ @fry sure, but I like python2 better ;) \$\endgroup\$undergroundmonorail– undergroundmonorail2014年12月19日 15:14:20 +00:00Commented Dec 19, 2014 at 15:14
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
-
\$\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– Dennis2014年12月19日 03:29:10 +00:00Commented Dec 19, 2014 at 3:29 -
\$\begingroup\$ @Dennis Yeah, the bug is weird. Thanks for the workaround ! \$\endgroup\$Optimizer– Optimizer2014年12月19日 07:01:29 +00:00Commented Dec 19, 2014 at 7:01
-
2\$\begingroup\$ this indentation in the expansion is so easy to read! You should reverse it! \$\endgroup\$DLeh– DLeh2014年12月19日 21:08:42 +00:00Commented Dec 19, 2014 at 21:08
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>
-
1\$\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
\swith a space character), and removing the parentheses aroundxin the replace function. \$\endgroup\$NinjaBearMonkey– NinjaBearMonkey2014年12月19日 01:57:08 +00:00Commented Dec 19, 2014 at 1:57 -
\$\begingroup\$ @hsl gee, thanks! I don't even know why I wrote
(x):/ \$\endgroup\$Optimizer– Optimizer2014年12月19日 07:06:06 +00:00Commented Dec 19, 2014 at 7:06 -
\$\begingroup\$ You don't need both
bandcdo you? They just refer to the same array anyway. \$\endgroup\$Neil– Neil2016年05月11日 15:00:15 +00:00Commented May 11, 2016 at 15:00
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.
Japt -R, 27 bytes
·
mâ\S
Vâ n
Ëx2 iSpWg~WbVgE
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
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]
Scala, (削除) 176 (削除ここまで)171
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'
}
}
PowerShell, 112 bytes
$x=@($args|sls '(?m)^ *'-a|% m*|% v*|sort -u)
[regex]::Replace($args,'(?m)^ *',{$x[-1-$x.IndexOf($args.Value)]})
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
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.
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>
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.