Stringhe topografiche


23

Ecco alcuni esempi di input, quindi posso spiegare qual è il problema:

((1 2)(3 (4 5) moo)) (i (lik(cherries)e (woohoo)))

Pensa a questa riga di testo come a una mappa topografica di alcune montagne. Ogni serie di parentesi mostra un'unità di altitudine.

Se "visualizziamo" questo dal lato, in modo da vedere le montagne in verticale, vedremo:

          4 5                cherries    woohoo  
  1 2  3       moo       lik          e
                      i

Data una di queste mappe topografiche, genera la mappa, ma su una scala verticale, come l'output sopra. Separare i diversi elementi nella mappa con il numero di caratteri per l'elemento successivo. Ad esempio, ci sono 4 spazi nell'output tra mooe i. Allo stesso modo, ci sono 4 caratteri nell'input tra mooe i.

Vince il codice che lo fa nel minor numero di caratteri.


È sicuro supporre che le altezze siano sempre positive? Ad esempio, l'ingresso ((1 2))))))))))3deve essere non valido se sono proibite altezze negative.
Cristian Lupascu,

@ w0lf: sì, le parentesi corrisponderanno sempre.
beary605,

Risposte:


10

J, 87 79 72 70 67 57 56 caratteri

'( ) 'charsub|.|:(+/\@('('&=-')'&=)(],~' '$~[)"0])1!:1[1

Riceve input dalla tastiera. Esempio:

   '( ) 'charsub|.|:(+/\@('('&=-')'&=)(],~' '$~[)"0])1!:1[1
((1 2)(3 (4 5) moo)) (i (lik(cherries)e (woohoo)))
          4 5                cherries    woohoo
  1 2  3       moo       lik          e
                      i

Spiegazione:

Questa spiegazione si basa sulla prima versione del mio programma:

|.|:('( ) 'charsub x)((' '$~{.@]),[{~{:@])"1(('('&([:+/=)-')'&([:+/=))\,.i.@#)x=.1!:1[1

x=.1!:1[1Prendi l'input dalla tastiera e inseriscilo xper dopo

(('('&([:+/=)-')'&([:+/=))\,.i.@#)crea un elenco di tutti gli indici nella stringa ( i.@#) e lo ricama ( ,.) insieme al risultato del (('('&([:+/=)-')'&([:+/=))\verbo.

(('('&([:+/=)-')'&([:+/=))\questo verbo viene applicato a tutti i prefissi della stringa (così via di ingresso helloche si applicherebbe a h, he, hel, hell, e hello. Si tratta di una forchetta , che conta il numero di parentesi aperte ('('&([:+/=)e quindi sottrae il numero di staffe stretti ')'&([:+/=). Questo mi dà la lista di indeci nella stringa e il livello in cui dovrebbe trovarsi il carattere di quell'indice nell'output. Con un input semplice questo mi dà quanto segue:

   (('('&([:+/=)-')'&([:+/=))\,.i.@#)x=.1!:1[1
(one(two(three)))
1  0
1  1
1  2
1  3
2  4
2  5
2  6
2  7
3  8
3  9
3 10
3 11
3 12
3 13
2 14
1 15
0 16

((' '$~{.@]),[{~{:@])"1questo è un verbo che prende l'elenco che ho appena generato e anche l'output di ('( ) 'charsub x)(che fa solo una sostituzione di stringa per sostituire tutte le parentesi con spazi in x). Prende la coda di ogni elemento dell'elenco {:@]e lo usa come indice nella stringa per ottenere il carattere [{~{:@]. Quindi lo prefigura ,con il numero di spazi come indicato dalla testa di ciascun elemento nell'elenco (' '$~{.@]). Nell'esempio precedente questo mi dà:

   ('( ) 'charsub x)((' '$~{.@]),[{~{:@])"1(('('&([:+/=)-')'&([:+/=))\,.i.@#)x=.1!:1[1
(one(two(three)))

 o
 n
 e

  t
  w
  o

   t
   h
   r
   e
   e

Traspongo quindi l'array |:e lo inverto |.per ottenere l'output desiderato.


6

GolfScript 69

0:§;{.'()'?))3%(.§+:§' ':s*\@s\if\n}%n/.{,}%$)\;:μ;{.,μ\-s*\+}%zip n*

Demo online qui .

Spiegazione:

0:§;                # declare the variable §, representing the 
                    # current vertical level and initialize it at 0

{                   # iterate for each char in the string:

    .'()'?))3% (    # add on the stack the amount by which
                    # the current vertical level should be 
                    # adjusted:
                    #   * +1 if the character is '('
                    #   * -1 if the character is ')'
                    #   * 0 otherwise

    .§+:§           # adjust the value of §

    ' ':s*          # add as many spaces as § tells us
                    # and save the space in variable s

    \@s\if\         # return current char, if it's printable,
                    # or a space if it's '(' or ')'

    n               # add a newline char

}%

n/                  # split by newline char; now we have 
                    # an array of strings on the stack.
                    # Each string is a vertical line of the
                    # final output.

.{,}%$)\;:μ;        # Iterate through the strings and find the
                    # maximum length

{
    .,μ\-s*\+       # Add spaces at the end to make all the strings 
                    # the same length
}%

zip                 # Transpose the strings

n*                  # Join the transposed strings by newline characters

@Gareth Sì, lo facciamo entrambi :)
Cristian Lupascu,

Vuoi aggiungere una spiegazione su come funziona?
Timwi,

@Timwi Ho modificato la mia risposta per includere una spiegazione
Cristian Lupascu,

5

APL (59)

⊖↑{⊃,/T\¨⍨⍵×P=0}¨R∘=¨(⍴T)∘⍴¨⍳⌈/R←1++\P←+/¨1 ¯1∘ר'()'∘=¨T←⍞

Ho ipotizzato che anche la "base" debba essere utilizzabile. (ie (a(b))c(d)è valido). Se ciò non è necessario, è possibile salvare due caratteri.

Spiegazione:

  • T←⍞: memorizza una riga di input in T
  • '()'∘=¨T: per ogni personaggio in T, vedi se si tratta di una parentesi aperta o chiusa. Questo fornisce un elenco di elenchi di booleani.
  • 1 ¯1∘ר: moltiplica il secondo elemento in ciascuna di queste liste per -1 (quindi una parentesi aperta è 1, una chiusura è -1 e ogni altro carattere è 0).
  • +/¨: prende la somma di ogni elenco interno. Ora abbiamo il valore ∆y per ogni personaggio.
  • P←: negozio in P.
  • R←1++\P: prende un totale parziale di P, dando l'altezza per ogni personaggio. Aggiungi uno a ciascun personaggio in modo che i caratteri al di fuori delle parentesi si trovino sulla prima riga.
  • (⍴T)∘⍴¨⍳⌈/R: per ogni possibile valore y, crea un elenco lungo quanto T, costituito solo da quel valore. (ovvero 1111 ..., 2222 ...., ecc.)
  • R∘=¨: per ogni elemento in questo elenco, vedi se è uguale a R. (Per ogni livello, ora abbiamo un elenco di zeri e di uno corrispondente alla presenza o meno di un personaggio su quel livello).
  • ⍵×P=0: per ciascuno di questi elenchi, impostarlo su zero se P non è zero in quel punto. Questo elimina i personaggi con un delta-y diverso da zero, in modo da eliminare le parentesi.
  • ⊃,/T\¨⍨: per ogni profondità, selezionare da T i caratteri che dovrebbero apparire.
  • ⊖↑: crea una matrice e mettila con il lato destro rivolto verso l'alto.

Quale implementazione APL stai usando? È gratis?
FUZxxl,

@FUZxxl Sto usando Dyalog APL, la versione di Windows può essere scaricata gratuitamente.
Marin

5

Tcl, 50

puts \33\[9A[string map {( \33\[A ) \33\[B} $argv]

Tipo di imbroglio, ma bene ..

Uso le sequenze di escape ASCII per ottenere la differenza di riga, ^[[Asignifica spostare il cursore 1 riga in alto, ^[[Bspostare il cursore 1 riga in basso.


5

APL, 41 caratteri / byte *

{⊖⍉⊃(↑∘''¨-⌿+/¨p∘.=,\⍵),¨⍵/⍨1-2×⍵∊p←'()'}

Testato su Dyalog, con a ⎕IO←1e ⎕ML←3ambiente. È una funzione che accetta l'input richiesto e restituisce l'output. Data la formulazione della domanda, credo che sia accettabile. In caso contrario, ecco una versione che legge da stdin e scrive su stdout, per altri 4 caratteri:

⍞←⊖⍉⊃(↑∘''¨-⌿+/¨'()'∘.=,\a),¨a/⍨1-2×'()'∊⍨a←⍞

Spiegazione :

{                                 p←'()'}  p is the string made of two parentheses
                                ⍵∊ ______  check which characters from ⍵ are parens
                            1-2× ________  -1 for every par., 1 for every other char
                         ⍵/⍨ ____________  replace () with spaces in the orig. string
    (                 ),¨ _______________  append every char to the following items
                   ,\⍵ _____________________  for every prefix of the original string
               p∘.= ________________________  check which chars are '(' and which ')'
            +/¨ ____________________________  sum: compute the number of '(' and ')'
          -⌿ _______________________________  subtract the no. of ')' from that of '('
     ↑∘''¨ _________________________________  generate as many spaces as that number
 ⊖⍉⊃ ____________________________________  make it into a table, transpose and flip

Esempi:

topo '((1 2)(3 (4 5) moo)) (i (lik(cherries)e (woohoo)))'
          4 5                cherries    woohoo   
  1 2  3       moo       lik          e           
                      i                           

 

topo 'a  (  b ( c(d)e ) f  )  g'
            d            
          c   e          
      b           f      
a                       g

*: APL può essere salvato in una varietà di set di caratteri a byte singolo legacy che associano i simboli APL ai 128 byte superiori. Pertanto, ai fini del golf, un programma che utilizza solo caratteri ASCII e simboli APL può essere valutato come caratteri = byte.


Sto cercando il set di caratteri APL qui e non riesco a trovare il simbolo. Sembra una combinazione dei caratteri ¨e ~?
Gareth,

Ciao @Gareth No, non era in IBM APL2. Puoi trovarlo in Dyalog (commerciale, ma c'è una versione nagware sepolta nel loro sito Web, ed è abbastanza buona per il golf; IMHO il miglior APL disponibile oggi), Nars2000 (miglior APL open source), GNU APL e APL di Ngn , tra altri.
Tobia,

@Gareth Graficamente è la combinazione di ~e ¨, sebbene sia un personaggio diverso da entrambi. È un operatore chiamato Commute . Nella sua forma diadico invertirà gli argomenti della funzione diadica è applicato a: (5-2)=(2-⍨5). Come operatore monadico risulta una funzione diadica in monadic, duplicando all'argomento a destra: (2*2)=(*⍨2). Viene principalmente utilizzato per scrivere un flusso ininterrotto di funzioni da destra a sinistra, senza dover mettere parentesi attorno a espressioni di grandi dimensioni e saltare gli occhi intorno a esse. Nel golf è utile perché 3*⍨1-2è un personaggio in meno di (1-2)*3:-)
Tobia

2
Quindi è l'equivalente di ~in J allora.
Gareth,

3

J, 56 caratteri

'( ) 'charsub|.|:((,~#&' ')"0[:+/\1 _1 0{~'()'&i.)1!:1]1

Un altro 56 caratteri soluzione J ... io conto profondità traducendo (in ⁻1, )in 1 e tutti gli altri caratteri in 0, e poi prendendo la somma parziale di questo: [: +/\ 1 _1 0 {~ '()'&i.. Il resto è in gran parte simile alla soluzione di @ Gareth.


2

Python, 161 caratteri

S=raw_input()
R=range(len(S))
H=[S[:i].count('(')-S[:i].count(')')for i in R]+[0]
for h in range(max(H),0,-1):print''.join((' '+S[i])[H[i]==H[i+1]==h]for i in R)

2

Python, 130

a=[""]*9
l=8
i=0
for c in raw_input():o=l;l+=c==')';l-=c=='(';a[l]=a[l].ljust(i)+c*(o==l);i+=1
print"\n".join(filter(str.strip,a))

2

Ruby 1.9 (129)

Legge da stdin.

l=0
$><<gets.split('').map{|c|x=[?(]*99;x[l+=c==?(?-1:c==?)?1:0]=c;x}.transpose.map(&:join).*(?\n).tr('()',' ').gsub(/^\s+\n/,'')

3
Bello! hai scoperto un bug nell'evidenziatore Ruby :)
Cristian Lupascu,

Ho testato e l'evidenziazione SQL funziona meglio per il tuo programma.
Cristian Lupascu,

@ w0lf ah, hai ragione. Ho cambiato il valore //per ''cui il personaggio conta lo stesso ed evita l'insetto nell'evidenziatore.
Paul Prestidge,

2

C, 132 caratteri

char*p,b[999];n;
main(m){for(p=gets(memset(b,32,999));*p;++p)*p-41?*p-40?p[n*99]=*p:++n>m?m=n:0:--n;
for(;m;puts(b+m--*99))p[m*99]=0;}

La descrizione non è riuscita a specificare la quantità di input che la presentazione ha dovuto accettare per essere accettata, quindi ho optato per limiti che erano più coerenti con le mie esigenze di golf (mentre continuavo a lavorare con quello fornito come input di esempio). Consentitemi di cogliere l'occasione per ricordare alla gente che spesso è una buona idea specificare i massimi minimi nelle descrizioni delle sfide.

Ci sono due loop principali nel codice. Il primo ciclo estrae tutti i caratteri non parentesi sulla riga di output appropriata e il secondo ciclo stampa ogni riga.


1

C, 149 caratteri

#define S for(i=0;c=v[1][i++];)h+=a=c-'('?c-')'?0:-1:1,
c,i,h=0,m=0;main(int a,char**v){S m=h>m?h:m;for(;m;m--){S putchar(a||h-m?32:c);putchar(10);}}

corri con arg citato, egaout "((1 2) (3 (4 5) moo)) (i (lik (ciliegie) e (woohoo)))"


0

Ottava, 128

Molto simile alla mia ultima risposta ...

p=1;x=[0];y=input(0);for j=1:numel(y);p-=(y(j)==")");x(p,j)=y(j);p+=(y(j)=="(");end;x(x==40)=x(x==41)=x(x==0)=32;char(flipud(x))

Test

Ingresso: "((1 2)(3 (4 5) moo)) (i (lik(cherries)e (woohoo)))"

Produzione:

          4 5 ciliegie woohoo   
  1 2 3 moo lik e           
                      io                           

0

C #, 229 byte

Se non ci sono restrizioni sullo spazio verticale iniziale, puoi usarlo (rientrato per chiarezza). Inizializzerà il cursore in basso di una riga per ogni (trovato prima della stampa, quindi sposta il cursore in alto e in basso man mano che le parentesi vengono lette.

using C=System.Console;
class P{
    static void Main(string[]a){
        int l=a[0].Length,i=l;
        while(i>0)
            if(a[0][--i]=='(')C.CursorTop++;
        while(++i<l){
            char c=a[0][i];
            if(c=='('){
                c=' ';
                C.CursorTop--;
            }
            if(c==')'){
                c=' ';
                C.CursorTop++;
            }
            C.Write(c);
        }
    }
}

0

PowerShell , 120 119 byte

(($h=($c=$args|% t*y)|%{($l+=(1,-1)[$_-40])})|sort)[-1]..0|%{$x=0;$y=$_
-join($c|%{"$_ "[$h[$x++]-ne$y-or$_-in40,41]})}

Provalo online!

Effetti collaterali: caratteri &e 'cambia altezza come (e ), ma viene visualizzato. Confronta i risultati per:

&$f "((1 2)(3 (4 5) moo)) (i (lik(cherries)e (woohoo)))"
&$f "&&1 2'&3 &4 5' moo'' &i &lik&cherries'e &woohoo'''"

Meno golf:

$chars=$args|% toCharArray

$heights=$chars|%{
    $level+=(1,-1)[$_-40]       # 40 is ASCII for '(', 41 is ASCII for ')'
    $level
}

$maxHeight=($heights|sort)[-1]

$maxHeight..0|%{
    $x=0;$y=$_
    $line=$chars|%{
        "$_ "[$heights[$x++]-ne$y -or $_-in40,41]
    }
    -join($line)
}

-1

VB.net (per S&G)

Non è il più grazioso del codice.

Module Q
 Sub Main(a As String())
  Dim t = a(0)
  Dim h = 0
  For Each m In (From G In (t.Select(Function(c)
                                     h += If(c = "(", 1, If(c = ")", -1, 0))
                                     Return h
                                   End Function).Select(Function(y, i) New With {.y = y, .i = i}))
             Group By G.y Into Group
             Order By   y Descending
            Select Group.ToDictionary(Function(x) x.i)
               ).Select(Function(d) New String(
                          t.Select(Function(c,i)If(d.ContainsKey(i),If(c="("c Or c=")"c," "c,c)," "c)).ToArray))
   Console.WriteLine(m)
  Next
 End Sub
End Module
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.