Baca tanggal dalam notasi xkcd


49

Dalam xkcd-nya tentang format tanggal standar ISO 8601 Randall menyelinap di notasi alternatif yang agak aneh:

masukkan deskripsi gambar di sini

Angka-angka besar adalah semua digit yang muncul pada tanggal saat ini dalam urutan yang biasa, dan angka-angka kecil adalah indeks berbasis 1 dari kemunculan digit itu. Jadi contoh di atas mewakili 2013-02-27.

Mari kita mendefinisikan representasi ASCII untuk tanggal seperti itu. Baris pertama berisi indeks 1 hingga 4. Baris kedua berisi angka "besar". Baris ketiga berisi indeks 5 hingga 8. Jika ada beberapa indeks dalam satu slot, mereka terdaftar bersebelahan dari yang terkecil hingga yang terbesar. Jika ada paling banyak mindeks dalam slot tunggal (yaitu pada digit yang sama, dan di baris yang sama), maka setiap kolom harus memiliki m+1karakter lebar dan rata kiri:

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

Lihat juga tantangan rekan untuk pertobatan yang berlawanan.

Tantangan

Diberi tanggal dalam notasi xkcd, mengeluarkan tanggal ISO 8601 yang sesuai ( YYYY-MM-DD).

Anda dapat menulis sebuah program atau fungsi, mengambil input melalui STDIN (atau alternatif terdekat), argumen baris perintah atau argumen fungsi dan mengeluarkan hasilnya melalui STDOUT (atau alternatif terdekat), nilai pengembalian fungsi atau parameter function (out).

Anda dapat berasumsi bahwa input adalah tanggal yang valid antara tahun 0000dan 9999, termasuk.

Tidak akan ada spasi utama di input, tetapi Anda dapat mengasumsikan bahwa garis-garisnya diisi dengan spasi ke persegi panjang, yang berisi paling banyak satu kolom spasi tambahan.

Aturan standar berlaku.

Uji Kasus

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

11
Orang-orang yang menulis tanggal dalam format "kucing hitam" adalah kutukan keberadaan saya.
Carcigenicate

1
Maafkan ketidaktahuan saya, tetapi bagaimana tepatnya format aneh sesuai dengan tanggal? Tidak bisakah seumur hidup saya berhasil mengusahakan pola itu.
Tom Carpenter

2
@ TomCarpenter Baris bawah dan atas menunjukkan di mana angka-angka di garis tengah muncul di tanggal. Misal di 1atas 2, jadi digit pertama adalah 2. 2di atas 0, jadi digit kedua adalah 0. 3di atas 1, di 4atas 3, jadi kita dapatkan 2013sebagai empat digit pertama. Sekarang di 5bawah 0, jadi digit kelima adalah 0, 6dan 7keduanya di bawah 2, jadi keduanya adalah digit 2. Dan akhirnya, 8ada di bawah 7, jadi digit terakhir adalah 8, dan kita berakhir dengan 2013-02-27. (Tanda hubung tersirat dalam notasi xkcd karena kita tahu pada posisi apa mereka muncul.)
Martin Ender

Jawaban:


8

CJam, 35 byte

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

Coba di sini . Ini mengharapkan garis input diisi dengan spasi.

Penjelasan

llmembaca dua baris input, dan {1$e>}*melakukan "pemindaian" pada baris kedua: ia mengambil semua awalan inputnya dan menghitung maksimum setiap awalan. Untuk jalur input "0 1 2 7 8", ini mendorong "0001112227778". Tumpukan kami sekarang terlihat seperti ini:

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

Kita perlu menangkap kembali nilai-nilai ke dalam daftar sendiri menggunakan ]; ini menangkap baris pertama kami juga, jadi kami pop kembali menggunakan (, untuk mendapatkan

"0001112227778" "first line"

seperti yang diharapkan.

eelee+ menghitung baris ini, kemudian melakukan hal yang sama untuk baris input ketiga, dan menggabungkan hasilnya, meninggalkan sesuatu seperti ini di atas tumpukan:

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

Sekarang tumpukan kami adalah ["0001112227778" X]tempat Xdaftar yang disebutkan di atas.

Kami membalik setiap pasangan dalam X( Wf%), mengurutkan pasangan secara leksikografis ( $), dan meninggalkan 8 pasangan terakhir -8>. Ini memberi kita sesuatu seperti:

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

Ini berfungsi, karena pengurutan menempatkan semua pasangan dengan kunci '(spasi) sebelum semua digit dalam urutan menaik.

Ini adalah "posisi- x " dari karakter 12345678pada baris pertama dan ketiga: kita hanya perlu mengambil karakter dari baris kedua (modifikasi) kita yang secara vertikal sejajar dengannya.

Untuk melakukan ini, kita ambil setiap posisi ( Wf=), indeks ke dalam string yang kita buat sebelumnya ( \f=). Kami ada "20610222"di tumpukan sekarang: untuk menambahkan tanda hubung, pertama-tama kami membaginya menjadi segmen dengan panjang dua ( 2/), mencetak segmen pertama tanpa baris baru ( (o) dan bergabung dengan segmen yang tersisa dengan tanda hubung ( '-*).

EDIT : trik pemindaian keren, Martin! Disimpan empat byte.

EDIT 2 : menyimpan dua byte lagi dengan mengganti eelee+dengan l+ee; karya ini, karena garis semua memiliki panjang yang sama, dan daftar indeks di CJam secara otomatis modulo panjang daftar, sehingga indeks n+0, n+1, n+2... baik peta untuk 0, 1, 2...

EDIT 3 : Martin menyimpan byte lain pada langkah terakhir proses. Bagus!


6

Pyth, 48 43

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

Test Suite

Membutuhkan bantalan dengan spasi menjadi persegi panjang.

Saya tidak berpikir ini adalah pendekatan terbaik, tetapi pada dasarnya ini menulis nilai tengah ke indeks dalam sebuah string yang ditunjukkan oleh nilai atas atau bawah. Yah saya kira saya punya cukup waktu untuk bermain golf sebagian besar hal-hal yang jelas saya lihat. : P


4

JavaScript (ES7), 115

Fungsi anonim. Menggunakan string template, ada baris baru yang signifikan dan termasuk dalam jumlah byte.

Persyaratan: jalur input tengah tidak boleh lebih pendek dari yang pertama atau yang terakhir. Persyaratan ini dipenuhi ketika input diisi dengan spasi untuk membentuk persegi panjang.

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 117 menggunakan .map alih-alih pemahaman array

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

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

Cuplikan tes

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>


Selamat telah menjadi yang pertama untuk menyelesaikan kedua tantangan. :)
Martin Ender

3

Haskell, 125 106 103 byte

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]

Membutuhkan bantalan dengan ruang hingga persegi panjang penuh.

Contoh penggunaan: f " 1 3 24\n0 1 2 7 8 \n57 6 8 "-> "1878-02-08".

Bagaimana itu bekerja:

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

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

Uji kasus .


1

Perl, 154 byte

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}

Tidak digabungkan & dijelaskan

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

0

JavaScript (ES6), 131 byte

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

Penjelasan

Membutuhkan input untuk diisi dengan spasi untuk membentuk persegi panjang.

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

Uji


0

Powershell, 119 byte

$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 tes tidak digabungkan:

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

Keluaran:

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

0

Jelly , 38 byte

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

Cobalah online!

Helper hanya ada di sana untuk memudahkan input; ini sebenarnya adalah program lengkap. Pastikan untuk merawat :

  • Baris pertama dan terakhir ( '''), serta baris di sebelahnya (kosong, ada untuk kejelasan).
    • Format input aktual tidak memiliki baris kosong kedua dan kedua dari belakang, dan string dimulai dan berakhir tepat di sebelah tanda kutip, tanpa baris baru di antara, seperti ini:
      '' '1 3 24
      0 1 2 7 8 
      57 6 8 '' '
      Anda dapat meninggalkan catatan kaki saat menggunakan format ini. Ini benar-benar string multi-line Python, dan tanda kutip diperlukan untuk beberapa input.
  • Pad input dengan spasi tambahan! Setiap output yang benar tanpa input yang benar benar sepenuhnya kebetulan, dan tidak didukung oleh saya.
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.