Leer una fecha en notación xkcd

49

En su xkcd sobre el formato de fecha estándar ISO 8601, Randall se coló en una notación alternativa bastante curiosa:

ingrese la descripción de la imagen aquí

Los números grandes son todos los dígitos que aparecen en la fecha actual en su orden habitual, y los números pequeños son índices basados ​​en 1 de las ocurrencias de ese dígito. Entonces el ejemplo anterior representa 2013-02-27.

Definamos una representación ASCII para tal fecha. La primera línea contiene los índices 1 a 4. La segunda línea contiene los dígitos "grandes". La tercera línea contiene los índices del 5 al 8. Si hay varios índices en una sola ranura, se enumeran uno al lado del otro de menor a mayor. Si hay como máximo míndices en una sola ranura (es decir, en el mismo dígito y en la misma fila), entonces cada columna debe tener m+1caracteres anchos y alineados a la izquierda:

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

Vea también el desafío complementario para la conversión opuesta.

El reto

Dada una fecha en notación xkcd, envíe la fecha ISO 8601 correspondiente ( YYYY-MM-DD).

Puede escribir un programa o función, tomando la entrada a través de STDIN (o la alternativa más cercana), argumento de línea de comando o argumento de función y generando el resultado a través de STDOUT (o la alternativa más cercana), el valor de retorno de la función o el parámetro de función (out).

Puede suponer que la entrada es cualquier fecha válida entre años 0000e 9999inclusive.

No habrá espacios iniciales en la entrada, pero puede suponer que las líneas se rellenan con espacios en un rectángulo, que contiene como máximo una columna de espacios final.

Aplican reglas estándar de .

Casos de prueba

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
fuente
11
Las personas que escriben la fecha en el formato "gato negro" son la ruina de mi existencia.
Carcigenicate
1
Perdone mi ignorancia, pero ¿cómo se corresponde exactamente el formato extraño con la fecha? No puedo por mi vida resolver el patrón.
Tom Carpenter
2
@TomCarpenter La línea inferior y superior indican dónde aparecen los números en la línea central en la fecha. Por ejemplo, 1está arriba 2, entonces el primer dígito es 2. 2está arriba 0, entonces el segundo dígito es 0. 3está arriba 1, 4está arriba 3, así que obtenemos 2013los primeros cuatro dígitos. Ahora 5está abajo 0, entonces el quinto dígito está 0, 6y 7ambos están abajo 2, entonces ambos dígitos están 2. Y finalmente, 8está abajo 7, así que el último dígito es 8, y terminamos con 2013-02-27. (Los guiones están implícitos en la notación xkcd porque sabemos en qué posiciones aparecen).
Martin Ender

Respuestas:

8

CJam, 35 bytes

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

Probar aquí . Espera que las líneas de entrada se rellenen con espacios.

Explicación

lllee dos líneas de entrada y {1$e>}*realiza una "exploración" en la segunda: toma todos los prefijos de su entrada y calcula el máximo de cada prefijo. Para la línea de entrada "0 1 2 7 8", esto empuja "0001112227778". Nuestra pila ahora se ve así:

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

Necesitamos volver a capturar los valores en una lista que usamos nosotros mismos ]; esto también captura nuestra primera línea, así que la sacamos de nuevo usando (, para obtener

"0001112227778" "first line"

como se esperaba.

eelee+ enumera esta línea, luego hace lo mismo para una tercera línea de entrada y concatena los resultados, dejando algo como esto en la parte superior de la pila:

[[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]]

Ahora nuestra pila es ["0001112227778" X]donde Xestá la lista enumerada arriba.

Volteamos cada par en X( Wf%), ordenamos los pares lexicográficamente ( $) y dejamos los últimos 8 pares -8>. Esto nos da algo como:

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

Esto funciona, porque la clasificación coloca todos los pares con clave '(espacio) antes de todos los dígitos en orden ascendente.

Estas son las " posiciones x " de los caracteres 12345678en la primera y tercera línea: solo necesitamos recuperar los caracteres de nuestra segunda línea (modificada) que están alineados verticalmente con ellos.

Para hacer esto, tomamos cada posición ( Wf=), indexamos en la cadena que hicimos anteriormente ( \f=). Ahora tenemos "20610222"en la pila: para agregar los guiones, primero nos dividimos en segmentos de longitud dos ( 2/), imprimimos el primer segmento sin una nueva línea ( (o) y unimos los segmentos restantes con guiones ( '-*).

EDITAR : ¡genial truco de escaneo, Martin! Guardado cuatro bytes.

EDIT 2 : guardado dos bytes más al reemplazar eelee+con l+ee; esto funciona, porque las líneas todos tienen la misma longitud, y la lista de indexación en Cjam es modulo automáticamente la longitud de la lista, por lo que los índices n+0, n+1, n+2... bien se asignan a 0, 1, 2...

EDITAR 3 : Martin guardó otro byte en el paso final del proceso. ¡Agradable!

Lynn
fuente
6

Pyth, 48 43

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

Banco de pruebas

Requiere relleno con espacios en un rectángulo.

No creo que este sea el mejor enfoque, pero básicamente escribe el valor medio en el índice en una cadena señalada por el valor superior o inferior. Bueno, supongo que tuve tiempo suficiente para jugar al golf la mayoría de las cosas obvias que vi. :PAGS

FryAmTheEggman
fuente
4

JavaScript (ES7), 115

Función anónima. Usando cadenas de plantilla, hay una nueva línea que es significativa e incluida en el conteo de bytes.

Requisito: la línea de entrada central no puede ser más corta que la primera o la última. Este requisito se cumple cuando la entrada se rellena con espacios para formar un rectá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 versión 117 usando .map en lugar de comprensión 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 golf

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

Fragmento de prueba

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
fuente
Felicidades por ser el primero en resolver ambos desafíos. :)
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]

Requiere relleno con espacios para un rectángulo completo.

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

Cómo 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
fuente
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 prueba .

Michał Perłakowski
fuente
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 y explicado

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
fuente
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``

Explicación

Requiere que la entrada se rellene con espacios para formar un rectá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

Prueba

usuario81655
fuente
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 prueba sin golf:

$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"
}

Salida:

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
mazzy
fuente
0

Jalea , 38 bytes

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

Pruébalo en línea!

El ayudante solo está allí para facilitar la entrada; Este es en realidad un programa completo. Asegúrese de cuidar :

  • La primera y la última línea ( '''), así como las líneas al lado de ellas (vacías, para mayor claridad).
    • El formato de entrada real no tiene la segunda y penúltimas líneas vacías, y la cadena comienza y termina directamente al lado de las comillas, sin una nueva línea intermedia, como esta:
      '' '1 3 24
      0 1 2 7 8 
      57 6 8 '' '
      Puede dejar el pie de página mientras usa este formato. Esta es realmente una cadena de varias líneas de Python, y las comillas son necesarias para algunas entradas.
  • Rellene la entrada con espacios finales! Cualquier salida correcta sin entrada correctamente acolchada es una coincidencia y no estoy respaldada por mí.
Erik el Outgolfer
fuente