Recuo reverso


63

Ouvi dizer que seu código pode ser executado mais rapidamente se você o recuar de forma inversa, para que o compilador possa processá-lo como um padrão de design de árvore do topo dos "ramos" para baixo. Isso ajuda porque a gravidade acelerará o tempo necessário para a compilação do seu código e a eficiência da estrutura de dados será aprimorada. Aqui está um exemplo, em scripts Java:

            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;
            }

Mas, por alguma razão, o Bloco de Notas não tem uma configuração para fazer isso automaticamente, então preciso de um programa para fazer isso por mim.

Descrição

Os envios devem usar um trecho de código como entrada, reverter o recuo e gerar o código resultante.

Isso é feito pelo seguinte procedimento:

  • Divida o código em linhas. Cada linha começará com zero ou mais espaços (não haverá tabulações).

  • Encontre todos os níveis de indentação exclusivos no código. Por exemplo, para o exemplo acima, isso seria

    0
    4
    8
    12
    
  • Inverta a ordem desta lista de níveis de indentação e mapeie a lista invertida para a lista original. Isso é difícil de explicar em palavras, mas, por exemplo, pareceria

    0  — 12
    4  — 8
    8  — 4
    12 — 0
    
  • Aplique esse mapeamento ao código original. No exemplo, uma linha com recuo de espaço 0 seria recuada por 12 espaços, 4 espaços se tornariam 8 espaços etc.

Entrada / Saída

A entrada e saída podem ser fornecidas como você desejar (STDIN / STDOUT, parâmetro de função / valor de retorno, etc.); se o seu idioma não suportar entrada |de várias linhas (ou você simplesmente não quiser), você poderá usar o caractere para separar as linhas.

A entrada consistirá apenas em novas linhas imprimíveis ASCII + e não conterá linhas vazias.

Casos de teste

Entrada:

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;
}

Saída: o código de exemplo acima.

Entrada:

a
  b
  c
d
   e
        f
  g
   h

Resultado:

        a
   b
   c
        d
  e
f
   g
  h

Entrada:

1
 2
  3
 2
1

Resultado:

  1
 2
3
 2
  1

Entrada:

  foo

Resultado:

  foo

21
Seu "JavaScript" e não "Java scripting": /
Otimizador

75
@Optimizer Vejo que meu objetivo de enfurecer o maior número possível de pessoas com os dois primeiros parágrafos foi alcançado. ;)
Maçaneta da porta

7
1! = Tantas pessoas quanto possível.
Optimizer

23
@JanDvorak Os mesmos caras que inventaram as citações no estilo MLA acham que é uma boa ideia.
Rainbolt

6
Supostamente, é mais rápido. Vamos atribuir um comitê a ele e esperar alguns anos enquanto esquecemos o seu objetivo.
Conor O'Brien

Respostas:


10

CJam, 43 39 36 35 bytes

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

Isso parece muito longo. Tenho certeza de que não estou otimizando o suficiente!

Como funciona:

A idéia básica é dividir a entrada na nova linha, calcular o número de espaços iniciais em cada linha, classificar e obter números únicos, copiar essa matriz e reverter a cópia, transliterar os números originais em ordem com essas duas matrizes e, finalmente, formar o string final usando essas informações.

A parte mais longa é descobrir quantos espaços iniciais existem em cada linha, pois o CJam não tem uma maneira fácil de fazê-lo.

Expansão do código:

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";

E no espírito da pergunta. Uma expansão real do código:

                                          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 salvos graças a Martin e 1 byte graças a Dennis

Experimente online aqui


1. {}#possui um erro: retorna um número inteiro, mas deve retornar um número longo. Ironicamente, i(convertido para inteiro) corrige isso. 2. Como ""#não possui o mesmo bug, _Sm0=#é um byte menor.
Dennis

@ Dennis Sim, o bug é estranho. Obrigado pela solução alternativa!
Optimizer

2
esse recuo na expansão é tão fácil de ler! Você deveria reverter isso!
precisa

13

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()

Recebe entrada com em |vez de \n.

Explicação

As três primeiras linhas são bastante diretas. Faça uma lista de todas as linhas da entrada, defina uma função que informe quanto espaço em branco inicial uma sequência possui e faça uma lista classificada de valores que a função é distribuída para cada linha de entrada.

A última linha é muito mais divertida.

                                 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


@frya thanks :)
undergroundmonorail

11
Isso tudo parece bem no python 3, que deve economizar 2 bytes (pagar 2 por ()salvar 4 raw_)
FryAmTheEggman

11
f(s)for s in ideveria ser map(f,i).
feersum

11
Um pedaço de mágica: d=[];d+=set(L)é uma versão mais curta do d=sorted(set(L)).
Xnor

7

JavaScript, ES6, 113 103 101 bytes

Tenho certeza de que isso pode ser jogado pelo menos um pouco mais, mas aqui vai.

Nunca teria pensado que haverá uma solução JS de 101 bytes, superando o 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]))

Isso cria um método chamado fque pode ser chamado com a sequência de entrada. Se você está em um Firefox mais recente, possui seqüências de modelos e pode chamar o método como

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

Caso contrário, você também pode chamá-lo como

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

ou tente o snippet abaixo:

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>


Você pode salvar os bytes de um cache armazenando o regex como uma variável, pois ele é usado duas vezes (você deve poder substituir \spor um caractere de espaço) e removendo os parênteses xna função de substituição.
NinjaBearMonkey

@hsl gee, obrigado! Eu nem sei por que escrevi (x): /
Optimizer

Você não precisa dos dois be precisa c? Eles apenas se referem à mesma matriz de qualquer maneira.
Neil

5

Ruby, 63 bytes

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

Isso define uma função sem nome que pega e retorna uma string. Você pode chamá-lo anexando ["string here"]ou atribuindo-o a uma variável e, em seguida, chamando essa variável.

Como funciona: s.scan(r=/^ */)fornece uma lista de todos os principais espaços e lojas que se regexam rpara uso posterior. uniqelimina duplicatas. sort... tipos.

Agora pule para o final, l.zip(l.reverse)dê uma matriz de pares que queremos substituir. to_htransforma isso em um hash, interpretando os pares como pares de valores-chave.

Agora s.gsubsubstituiu todas as correspondências da regex (todos os espaços à esquerda) usando esse hash como uma tabela de consulta para encontrar a substituição.



2

Japonês -R , 27 bytes

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

Experimente online!

Descompactado e como funciona

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

Como realmente funciona

                 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

1

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'}}

Ele adicionará uma nova linha extra no final. Se eu não tiver que preservar espaços no final da linha, posso obtê-lo para 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'
    }
      }

1

PowerShell , 112 bytes

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

Experimente online!

Menos golfe:

$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

0

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]

0

PHP - 173 bytes

O código não otimizado deve ser armazenado na $vvariável:

<?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);

Aqui está a versão não-gasta e comentada:

<?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);

Provavelmente nunca escrevi algo tão sujo. Estou envergonhado.


0

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);

Versão não destruída:

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);

Testando


0

Perl 5, 112

111 + 1 para -n( -Eé grátis)

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

Tenho certeza de que isso pode ser feito com menos pinceladas, mas não vejo como no momento.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.