Przeczytaj datę w notacji xkcd

49

W swoim xkcd na temat standardowego formatu daty ISO 8601 Randall napisał dość dziwną alternatywną notację:

wprowadź opis zdjęcia tutaj

Duże liczby to wszystkie cyfry, które pojawiają się w bieżącej dacie w ich zwykłej kolejności, a małe liczby są 1-wskaźnikowymi wskaźnikami występowania tej cyfry. Powyższy przykład reprezentuje 2013-02-27.

Zdefiniujmy reprezentację ASCII dla takiej daty. Pierwszy wiersz zawiera indeksy od 1 do 4. Drugi wiersz zawiera „duże” cyfry. Trzeci wiersz zawiera indeksy od 5 do 8. Jeśli w jednym gnieździe znajduje się wiele indeksów, są one wymienione obok siebie, od najmniejszej do największej. Jeśli mw jednym polu jest co najwyżej indeks (tj. Na tej samej cyfrze i w tym samym wierszu), każda kolumna powinna mieć m+1szerokość znaków i wyrównanie do lewej:

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

Zobacz także wyzwanie towarzyszące dla odwrotnej konwersji.

Wyzwanie

Podając datę w notacji xkcd, wypisz odpowiednią datę ISO 8601 ( YYYY-MM-DD).

Możesz napisać program lub funkcję, pobierając dane wejściowe przez STDIN (lub najbliższą alternatywę), argument wiersza poleceń lub argument funkcji i wypisując wynik przez STDOUT (lub najbliższą alternatywę), wartość zwracaną funkcji lub parametr funkcji (wyjściowej).

Można zakładać, że wejście jest jakaś ważna data w latach 0000i 9999włącznie.

Na wejściu nie będzie żadnych spacji wiodących, ale możesz założyć, że linie są wypełnione spacjami do prostokąta, który zawiera co najmniej jedną końcową kolumnę spacji.

Obowiązują standardowe zasady .

Przypadki testowe

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
źródło
11
Ludzie, którzy piszą datę w formacie „czarnego kota”, są zmorą mojego istnienia.
Carcigenicate,
1
Wybacz mi moją ignorancję, ale jak dokładnie ten dziwny format odpowiada dacie? Nie mogę dla mojego życia wypracować wzoru.
Tom Carpenter,
2
@TomCarpenter Dolny i górny wiersz wskazują, gdzie w środkowej linii pojawiają się liczby. Np. 1Jest powyżej 2, więc pierwsza cyfra to 2. 2jest powyżej 0, więc drugą cyfrą jest 0. 3jest powyżej 1, 4jest powyżej 3, więc otrzymujemy 2013jako pierwsze cztery cyfry. Teraz 5jest poniżej 0, więc piąta cyfra jest 0, 6i 7obie są poniżej 2, więc obie te cyfry są 2. I w końcu 8jest poniżej 7, więc ostatnia cyfra jest 8, a my kończymy na 2013-02-27. (Łączniki są ukryte w notacji xkcd, ponieważ wiemy, w jakich pozycjach się pojawiają.)
Martin Ender

Odpowiedzi:

8

CJam, 35 bajtów

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

Wypróbuj tutaj . Oczekuje, że linie wejściowe zostaną wypełnione spacjami.

Wyjaśnienie

llodczytuje dwa wiersze danych wejściowych i {1$e>}*wykonuje „skanowanie” na drugim: pobiera wszystkie prefiksy danych wejściowych i oblicza maksimum każdego prefiksu. W przypadku linii wejściowej "0 1 2 7 8"popycha to "0001112227778". Nasz stos wygląda teraz tak:

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

Musimy sami ponownie uchwycić wartości na liście ]; przechwytuje to także naszą pierwszą linię, więc wyskakujemy za pomocą (, aby uzyskać

"0001112227778" "first line"

zgodnie z oczekiwaniami.

eelee+ wylicza ten wiersz, a następnie robi to samo dla trzeciego wiersza wejściowego i konkatenuje wyniki, pozostawiając coś takiego na górze stosu:

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

Teraz nasz stos jest ["0001112227778" X], gdzie Xjest powyżej lista wyliczeniowy.

Przerzucamy każdą parę w X( Wf%), sortujemy pary leksykograficznie ( $) i zostawiamy ostatnie 8 par -8>. To daje nam coś takiego:

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

Działa to, ponieważ sortowanie umieszcza wszystkie pary z kluczem '(spacją) przed wszystkimi cyframi w porządku rosnącym.

Są to „ x- pozycje” znaków 12345678w pierwszym i trzecim wierszu: wystarczy pobrać znaki z naszej (zmodyfikowanej) drugiej linii, które są do nich wyrównane pionowo.

Aby to zrobić, bierzemy każdą pozycję ( Wf=), indeks do ciągu, który wykonaliśmy wcześniej ( \f=). Mamy "20610222"teraz na stosie: aby dodać kreski, najpierw dzielimy na segmenty o długości dwa ( 2/), drukujemy pierwszy segment bez nowej linii ( (o) i łączymy pozostałe segmenty z myślnikami ( '-*).

EDYCJA : fajna sztuczka skanowania, Martin! Zapisano cztery bajty.

EDIT 2 : zapamiętanych jeszcze dwa bajty, zastępując eelee+z l+ee; to działa, ponieważ linie wszyscy mają takie same długości i indeksacji w CJam lista jest automatycznie modulo długość listy, więc indeksy n+0, n+1, n+2... ładnie odwzorowane na 0, 1, 2...

EDYCJA 3 : Martin zapisał kolejny bajt na ostatnim etapie procesu. Miły!

Lynn
źródło
6

Pyth, 48 43

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

Pakiet testowy

Wymaga wypełnienia spacjami prostokąta.

Nie sądzę, że jest to najlepsze podejście, ale zasadniczo zapisuje środkową wartość do indeksu w ciągu wskazanym przez górną lub dolną wartość. Wydaje mi się, że miałem wystarczająco dużo czasu na grę w golfa w większości oczywistych rzeczy, które widziałem. : P

FryAmTheEggman
źródło
4

JavaScript (ES7), 115

Funkcja anonimowa. Używając ciągów szablonów, istnieje nowa linia, która jest znacząca i jest uwzględniona w liczbie bajtów.

Warunek: środkowy wiersz wejściowy nie może być krótszy niż pierwszy lub ostatni. To wymaganie jest spełnione, gdy dane wejściowe są wypełnione spacjami, aby utworzyć prostokąt.

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 wersja 117 z .map zamiast interpretacji tablic

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

Mniej golfa

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

Testowy fragment kodu

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
źródło
Gratulujemy pierwszego rozwiązania obu problemów. :)
Martin Ender,
3

Haskell, 125 106 103 bajty

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]

Wymaga wypełnienia spacjami do pełnego prostokąta.

Przykład użycia: f " 1 3 24\n0 1 2 7 8 \n57 6 8 "-> "1878-02-08".

Jak to działa:

[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
źródło
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``}

Przypadki testowe .

Michał Perłakowski
źródło
1

Perl, 154 bajtów

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}

Niegolfowane i wyjaśnione

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
źródło
0

JavaScript (ES6), 131 bajtów

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

Wyjaśnienie

Wymaga wypełnienia danych wejściowych spacjami w celu utworzenia prostokąta.

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

Test

użytkownik 81655
źródło
0

PowerShell, 119 bajtów

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

Skrypt testowy bez golfa:

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

Wynik:

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
źródło
0

Galaretka , 38 bajtów

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

Wypróbuj online!

Pomocnik jest tylko po to, aby ułatwić wprowadzanie; to właściwie pełny program. Pamiętaj, aby dbać o :

  • Pierwszy i ostatni wiersz ( '''), a także wiersze obok nich (puste, tam dla przejrzystości).
    • Rzeczywisty format wejściowy nie zawiera drugiej i przedostatniej pustej linii, a łańcuch zaczyna się i kończy bezpośrednio obok cudzysłowów, bez nowego wiersza pomiędzy nimi, jak poniżej:
      '1 3 24
      0 1 2 7 8 
      57 6 8 ''
      Możesz pozostawić stopkę podczas korzystania z tego formatu. To naprawdę jest wieloliniowy ciąg Pythona, a dla niektórych danych wejściowych niezbędne są cudzysłowy.
  • Wypełnij wejście spacjami! Każde prawidłowe wyjście bez poprawnie wypełnionego wejścia jest całkowicie przypadkowe i nie jest przeze mnie popierane.
Erik the Outgolfer
źródło