Leia uma data na notação xkcd

49

Em seu xkcd sobre o formato de data padrão ISO 8601, Randall se escondeu em uma notação alternativa bastante curiosa:

insira a descrição da imagem aqui

Os números grandes são todos os dígitos que aparecem na data atual em sua ordem usual, e os números pequenos são índices baseados em 1 das ocorrências desse dígito. Portanto, o exemplo acima representa 2013-02-27.

Vamos definir uma representação ASCII para essa data. A primeira linha contém os índices de 1 a 4. A segunda linha contém os dígitos "grandes". A terceira linha contém os índices 5 a 8. Se houver vários índices em um único slot, eles serão listados um do lado do outro, do menor para o maior. Se houver no máximo míndices em um único slot (ou seja, no mesmo dígito e na mesma linha), cada coluna deverá ter m+1caracteres largos e alinhados à esquerda:

2  3  1  4
0  1  2  3  7
5     67    8

Veja também o desafio associado para a conversão oposta.

O desafio

Dada uma data na notação xkcd, imprima a data ISO 8601 correspondente ( YYYY-MM-DD).

Você pode escrever um programa ou função, recebendo entrada via STDIN (ou alternativa mais próxima), argumento da linha de comando ou argumento da função e exibindo o resultado via STDOUT (ou alternativa mais próxima), valor de retorno da função ou parâmetro da função (saída).

Você pode assumir que a entrada é qualquer data válida entre anos 0000e 9999inclusive.

Não haverá espaços à esquerda na entrada, mas você pode assumir que as linhas são preenchidas com espaços em um retângulo, que contém no máximo uma coluna de espaços à direita.

Aplicam-se as regras de padrão .

Casos de teste

2  3  1  4
0  1  2  3  7
5     67    8
2013-02-27

2  3  1     4
0  1  2  4  5
   5  67 8
2015-12-24

     1234
1    2
5678
2222-11-11

   1     3  24
0  1  2  7  8
57    6     8
1878-02-08

2   4   1   3
0   1   2   6
5       678
2061-02-22

      1 4 2 3
0 1 2 3 4 5 6 8
6 5 7         8
3564-10-28

1234
1
5678
1111-11-11

1 2 3 4
0 1 2 3
8 5 6 7
0123-12-30
Martin Ender
fonte
11
As pessoas que escrevem a data no formato "gato preto" são a desgraça da minha existência.
Carcigenicate
11
Perdoe minha ignorância, mas como exatamente o formato estranho corresponde à data? Não é possível para a minha vida descobrir o padrão.
Tom Carpenter
2
@TomCarpenter A linha inferior e superior indicam onde os números na linha do meio aparecem na data. Por exemplo, 1está acima 2, então o primeiro dígito é 2. 2está acima 0, então o segundo dígito é 0. 3está acima 1, 4está acima 3, então obtemos 2013os quatro primeiros dígitos. Agora 5está abaixo 0, assim que o quinto dígito é 0, 6e 7são ambos abaixo 2, então ambos os dígitos são 2. E, finalmente, 8está abaixo 7, então o último dígito é 8, e terminamos com 2013-02-27. (Os hífens estão implícitos na notação xkcd porque sabemos em que posições eles aparecem.)
Martin Ender

Respostas:

8

CJam, 35 bytes

ll{1$e>}*](l+eeWf%$-8>Wf=\f=2/(o'-*

Experimente aqui . Ele espera que as linhas de entrada sejam preenchidas com espaços.

Explicação

lllê duas linhas de entrada e {1$e>}*executa uma "varredura" na segunda: pega todos os prefixos de sua entrada e calcula o máximo de cada prefixo. Para a linha de entrada "0 1 2 7 8", isso empurra "0001112227778". Nossa pilha agora fica assim:

"first line" '0 '0 '0 '1 '1 '1 ...

Precisamos capturar novamente os valores em uma lista usando ]; isso captura nossa primeira linha também, então a colocamos de volta usando (, para obter

"0001112227778" "first line"

como esperado.

eelee+ enumera essa linha, depois faz o mesmo para uma terceira linha de entrada e concatena os resultados, deixando algo assim no topo da pilha:

[[0 '5] [1 ' ] [2 ' ] [3 ' ] [4 ' ] [5 ' ] [6 ' ] [7 ' ] [8 '6] [9 '7] [10 '8] [11 ' ] [12 ' ]
 [0 '2] [1 ' ] [2 ' ] [3 ' ] [4 '4] [5 ' ] [6 ' ] [7 ' ] [8 '1] [9 ' ] [10 ' ] [11 ' ] [12 '3]]

Agora nossa pilha é ["0001112227778" X]onde Xestá a lista enumerada acima.

Viramos cada par em X( Wf%), classificamos os pares lexicograficamente ( $) e deixamos os últimos 8 pares -8>. Isso nos dá algo como:

[['1 8] ['2 0] ['3 12] ['4 4] ['5 0] ['6 8] ['7 9] ['8 10]]

Isso funciona porque a classificação coloca todos os pares com a tecla '(espaço) antes de todos os dígitos em ordem crescente.

Estas são as " posições x " dos caracteres 12345678na primeira e terceira linhas: precisamos recuperar apenas os caracteres da nossa segunda linha (modificada) que está alinhada verticalmente com eles.

Para fazer isso, pegamos cada position ( Wf=), indexamos na string que criamos anteriormente ( \f=). Agora temos "20610222"na pilha: para adicionar os traços, primeiro dividimos em segmentos de comprimento dois ( 2/), imprima o primeiro segmento sem uma nova linha ( (o) e junte os segmentos restantes com traços ( '-*).

EDIT : truque de varredura legal, Martin! Salvo quatro bytes.

EDIT 2 : salvou mais dois bytes substituindo eelee+por l+ee; isso funciona, porque as linhas têm o mesmo comprimento, e lista de indexação em CJam é automaticamente módulo o comprimento lista, de modo que os índices n+0, n+1, n+2... bem mapear para 0, 1, 2...

EDIT 3 : Martin salvou outro byte na etapa final do processo. Agradável!

Lynn
fonte
6

Pyth, 48 43

j\-cj\-ctuuXN.xsTZK?qJhtHdKJ+hHeHGC.z*9d4 7

Suíte de teste

Requer preenchimento com espaços em um retângulo.

Eu não acho que essa seja a melhor abordagem, mas basicamente ela grava o valor do meio no índice em uma string apontada pelo valor superior ou inferior. Acho que tive tempo suficiente para jogar golfe na maioria das coisas óbvias que vi. : P

FryAmTheEggman
fonte
4

JavaScript (ES7), 115

Função anônima. Usando cadeias de modelo, há uma nova linha que é significativa e incluída na contagem de bytes.

Requisito: a linha de entrada do meio não pode ser menor que a primeira ou a última. Este requisito é atendido quando a entrada é preenchida com espaços para formar um retângulo.

x=>([a,z,b]=o=x.split`
`,d=i=0,[for(c of z)o[a[i]-1]=o[b[i++]-1]=d=+c||d],o.splice(4,2,'-',o[4],o[5],'-'),o.join``)

ES6 versão 117 usando .map em vez de compreensão de matriz

x=>([a,z,b]=o=x.split`
`,d=0,[...z].map((c,i)=>o[a[i]-1]=o[b[i]-1]=d=+c||d],o.splice(4,2,'-',o[4],o[5],'-'),o.join``)

Menos golfe

x=>(
  o=[],
  [a,z,b] = x.split`\n`,
  d=i=0,
  [ for(c of z) (
      d = +c||d, // each new digit found in z goes in d (but not the spaces and not the '0' (d starts at 0 anyway)
      o[a[i]-1] = o[b[i]-1] = d, // if the index char is space, that gives index -1 that is ignored when joining later
      ++i
  )],
  o.splice(4,2,'-',o[4],o[5],'-'), // add the dashes in the right places
  o.join``
)

Snippet de teste

f=x=>(
  [a,z,b]=o=x.split`\n`,
  d=i=0,[for(c of z)o[a[i]-1]=o[b[i++]-1]=d=+c||d],
  o.splice(4,2,'-',o[4],o[5],'-'),o.join``
)


console.log=x=>O.textContent+=x+'\n';

[['2  3  1  4\n0  1  2  3  7\n5     67    8','2013-02-27']
,['2  3  1     4\n0  1  2  4  5\n   5  67 8','2015-12-24']
,['      1234\n1     2   \n5678','2222-11-11']
,['   1     3  24\n0  1  2  7  8 \n57    6     8','1878-02-08']
,['2   4   1   3\n0   1   2   6  \n5       678','2061-02-22']
,['      1 4 2 3\n0 1 2 3 4 5 6 8\n6 5 7         8','3564-10-28']
,['1234\n1   \n5678','1111-11-11']
,['1 2 3 4\n0 1 2 3\n8 5 6 7','0123-12-30']]
.forEach(t=>(k=t[1],r=f(t[0]),console.log(t[0]+'\n'+r+'\n'+(r==k?'OK\n':'Fail\n'))))
<pre id=O></pre>

edc65
fonte
Parabéns por ser o primeiro a resolver os dois desafios. :)
Martin Ender
3

Haskell, 125 106 103 bytes

a#' '=a
a#b=b
f i|[a,b,c]<-('-':)<$>lines i=[o|m<-"1234-56-78",(n,o,p)<-zip3 a(scanl1(#)b)c,m==n||m==p]

Requer preenchimento com espaços para um retângulo completo.

Exemplo de uso: f " 1 3 24\n0 1 2 7 8 \n57 6 8 "-> "1878-02-08".

Como funciona:

[a,b,c]<-('-':)<$>lines i          -- split input into lines, prepend a '-' to
                                   -- each, call them a, b and c
               (scanl1(#)b)        -- fill spaces of the middle line with the
                                   -- previous char, e.g.
                                   -- "-0  1  2  7  8 " -> "-00011122277788"
        zip3 a (scanl...) c        -- combine the lines element wise into triples.
                                   -- This is our lookup table for "1234-56-78" 
o|m<-"1234...",  (n,o,p)<-zip...,  m==n||m==p
                                   -- whenever m equals n or p (i.e. was originally
                                   -- in the first or last line), take the
                                   -- corresponding char o (middle line)
nimi
fonte
2

JavaScript ES6, 231

a=>{r=[];var b=[d,f,e]=a.split`
`.map(n=>n.split``);Array(Math.max(...b.map(n=>n.length))).fill().map((m,i)=>{(m=f[i])&&m!=" "&&(c=m);[d,e].map(m=>(g=m[i])&&g!=" "&&(r[g-1]=c))}),r.splice(4,0,"-"),r.splice(7,0,"-");return r.join``}

Casos de teste .

Michał Perłakowski
fonte
1

Perl, 154 bytes

sub{$_=$_[1];@n=/\d/g;/ +/;map{map{$p[$i++].=$_}unpack"(a$+[0])*";$i=0}@_[0,2];map{map{$r[$_-1]=$n[$i]if/\d/}s plit$"='';$i++}@p;"@r"=~s/....\K(..)/-$1-/r}

Ungolfed & Explained

sub{
    $_=$_[1]; # $_[1] is 2nd argument (i.e., 2nd line)
    @n=/\d/g; # @n now contains all digits in 2nd line
    / +/;     # $+[0] now the chunk length in 2nd line
              # Equivalent to /( +)/;$l = 1 + length $1;
    map{      # Perl golfer's for-loop
        map{ 
            $p[$i++] .= $_    # @p contains positions of each digit
        } unpack "(a$+[0])*"; # Split line into same chunk width
        $i=0 # At end of loop so we don't need $i=0 before next one
    } @_[0,2];# Outer map works on 1st and 3rd lines
    map{
        map{
            # Shove $n[$i] into ($_-1)th slot in @r if $_ is a number
            $r[$_-1] = $n[$i] if /\d/
        } split $"=''; # Equivalent to split '', but sets $"='' for free
        $i++
    }@p;
    # Concatenate @r, convert 20130227 to 2013-02-27, and return
    "@r"=~s/....\K(..)/-$1-/r
};
type_outcast
fonte
0

JavaScript (ES6), 131 bytes

s=>[...(r=[,,,,"-",,,"-"],l=s.split`
`)[1]].map((c,i)=>(c>"-"?n=c:0,y=+l[0][i],d=+l[2][i],y?r[y-1]=n:0,d?r[d+(d>6)]=n:0))&&r.join``

Explicação

Requer que a entrada seja preenchida com espaços para formar um retângulo.

s=>
  [...(
    r=[,,,,"-",,,"-"], // r = array of result characters, prefill with "-" symbols
    l=s.split`
`                      // l = array of lines
  )[1]].map((c,i)=>(   // for each character on the middle line
    c>"-"?n=c:0,       // n = the most recent digit encountered
    y=+l[0][i],        // y = index on the year line at the current position
    d=+l[2][i],        // d = index on the date line at the current position
    y?r[y-1]=n:0,      // if y is a number, put n at the index y of the result
    d?r[d+(d>6)]=n:0   // if d is a number, put n at the index d (accounting for "-"s)
  ))
  &&r.join``           // return the result as a string

Teste

user81655
fonte
0

Powershell, 119 bytes

$r=,'-'*99
($a=$args-split'
')[1]|% t*y|%{if($_-32){$d=$_}
$a[0,2]|%{$r[$_[+$p]-48]=$d}
$p++}
-join$r[1..4+0+5+6+0+7+8]

Script de teste não destruído:

$f = {

$r=,'-'*99                       # init a result as an array of '-' repeated 99 times
($a=$args-split"`n")[1]|% t*y|%{ # split argument string, store a top, middle and bottom to $a, then for each char of the middle line...
    if($_-32){$d=$_}             # store a digit to $d if the current character of the middle is not a space
    $a[0,2]|%{                   # for the top and the bottom lines...
        $r[$_[+$p]-48]=$d        # store a digit to the result array
    }                            # Note: if char in the current position is a space, then expression $_[+$p]-48 less then 0.
                                 # In this case, the expression $r[32-48]=$d changes unused element in a end of the array.
                                 # That is why the array was created by a large.
    $p++                         # next position
}
-join$r[1..4+0+5+6+0+7+8]        # return joined char with specified numbers
                                 # Note: element with index 0 has value '-'
}

@(
,(@"
2  3  1  4   
0  1  2  3  7
5     67    8
"@,"2013-02-27")

,(@"
2  3  1     4
0  1  2  4  5
    5  67 8  
"@,"2015-12-24")

,(@"
     1234
1    2   
5678     
"@,"2222-11-11")

,(@"
1     3  24
0  1  2  7  8 
57    6     8 
"@,"1878-02-08")

,(@"
2   4   1   3
0   1   2   6
5       678  
"@,"2061-02-22")

,(@"
      1 4 2 3  
0 1 2 3 4 5 6 8
6 5 7         8
"@,"3564-10-28")

,(@"
1234
1   
5678
"@,"1111-11-11")

,(@"
1 2 3 4
0 1 2 3
8 5 6 7
"@,"0123-12-30")

) | % {
    $a,$expected = $_
    $result = &$f $a
    "$(""$result"-eq"$expected"): $result"
}

Resultado:

True: 2013-02-27
True: 2015-12-24
True: 2222-11-11
True: 1878-02-08
True: 2061-02-22
True: 3564-10-28
True: 1111-11-11
True: 0123-12-30
confuso
fonte
0

Gelatina , 38 bytes

Ỵṙ-Zn⁶Ṫ€œṗƊḊZḟ⁶V€$€;2/p/Ʋ€ẎṢṪ€s2Ḣ;jɗ”-

Experimente online!

O ajudante está lá apenas para facilitar a entrada; este é realmente um programa completo. Certifique-se de cuidar de :

  • A primeira e a última linhas ( '''), bem como as linhas próximas a elas (vazias, para maior clareza).
    • O formato de entrada real não possui a segunda e penúltima linha vazia, e a sequência começa e termina diretamente ao lado das aspas, sem uma nova linha intermediária, como esta:
      1 3 24
      0 1 2 7 8 
      57 6 8 ''
      Você pode deixar o rodapé enquanto estiver usando este formato. Esta é realmente uma string de múltiplas linhas do Python, e as aspas são necessárias para algumas entradas.
  • Almofada a entrada com espaços à direita! Qualquer saída correta sem entrada preenchida corretamente é inteiramente coincidência e não é recomendada por mim.
Erik, o Outgolfer
fonte