Прочитать дату в нотации xkcd

49

В своем xkcd о стандартном формате даты ISO 8601 Рэндалл вырвался в довольно любопытной альтернативной записи:

введите описание изображения здесь

Большие числа - это все цифры, которые появляются в текущей дате в их обычном порядке, а маленькие цифры - это индексы, основанные на 1, вхождения этой цифры. Таким образом, приведенный выше пример представляет 2013-02-27.

Давайте определим представление ASCII для такой даты. Первая строка содержит индексы с 1 по 4. Вторая строка содержит «большие» цифры. Третья строка содержит индексы с 5 по 8. Если в одном слоте несколько индексов, они перечислены рядом друг с другом от наименьшего к наибольшему. Если mв одном слоте имеется не более индексов (т.е. в одной цифре и в одной строке), то каждый столбец должен иметь m+1ширину символов и выравниваться по левому краю:

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

Смотрите также сопутствующий вызов для обратного преобразования.

Соревнование

Учитывая дату в xkcd-нотации, выведите соответствующую дату ISO 8601 ( YYYY-MM-DD).

Вы можете написать программу или функцию, принимая ввод через STDIN (или ближайшую альтернативу), аргумент командной строки или аргумент функции и выводя результат через STDOUT (или ближайшую альтернативу), возвращаемое значение функции или параметр функции (out).

Вы можете предположить, что ввод является любой действительной датой между годами 0000и 9999включительно.

На входе не будет начальных пробелов, но вы можете предположить, что строки дополняются пробелами до прямоугольника, который содержит не более одного завершающего столбца пробелов.

Применяются стандартные правила .

Тестовые случаи

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
Люди, которые пишут дату в формате «черная кошка», являются проклятием моего существования.
Carcigenicate
1
Простите мое невежество, но как именно странный формат соответствует дате? Не могу на всю жизнь разработать шаблон.
Том Карпентер
2
@TomCarpenter Нижняя и верхняя строка показывают, где цифры в средней строке появляются в дате. Например 1, выше 2, поэтому первая цифра 2. 2выше 0, поэтому вторая цифра 0. 3выше 1, 4выше 3, поэтому мы получаем 2013первые четыре цифры. Теперь 5ниже 0, так что пятая цифра 0, 6и 7оба ниже 2, так что обе эти цифры 2. И, наконец, 8ниже 7, поэтому последняя цифра 8, и мы в конечном итоге 2013-02-27. (Дефисы неявны в нотации xkcd, потому что мы знаем, в каких позициях они появляются.)
Мартин Эндер

Ответы:

8

CJam, 35 байт

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

Попробуй это здесь . Ожидается, что входные строки будут дополнены пробелами.

объяснение

llчитает две строки ввода и {1$e>}*выполняет «сканирование» для второй: он берет все префиксы своего ввода и вычисляет максимум каждого префикса. Для строки ввода "0 1 2 7 8"это толкает "0001112227778". Наш стек теперь выглядит так:

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

Нам нужно заново записать значения в список, используя самих себя ]; это захватывает наша первая линия, так что мы вытолкнуть его обратно с помощью (, чтобы получить

"0001112227778" "first line"

как и ожидалось.

eelee+ перечисляет эту строку, затем делает то же самое для третьей входной строки и объединяет результаты, оставляя что-то вроде этого на вершине стека:

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

Теперь наш стек находится ["0001112227778" X]где Xперечисленный выше список.

Мы переворачиваем каждую пару в X( Wf%), сортируем пары лексикографически ( $) и оставляем последние 8 пар -8>. Это дает нам что-то вроде:

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

Это работает, потому что сортировка помещает все пары с ключом '(пробел) перед всеми цифрами в порядке возрастания.

Это « x- положения» символов 12345678в первой и третьей строках: нам нужно только извлечь символы из нашей (измененной) второй строки, которые выровнены по вертикали.

Для этого мы берем каждую позицию ( Wf=), указатель на строку, которую мы сделали ранее ( \f=). Теперь у нас "20610222"в стеке: чтобы добавить тире, сначала мы разбиваем на сегменты длиной два ( 2/), печатаем первый сегмент без новой строки ( (o) и соединяем оставшиеся сегменты с помощью тире ( '-*).

РЕДАКТИРОВАТЬ : крутой трюк сканирования, Мартин! Сохранено четыре байта.

РЕДАКТИРОВАТЬ 2 : сохранил еще два байта, заменив eelee+на l+ee; это работает, потому что линии все имеют одинаковую длину, и список индексация в CJam автоматически по модулю длине списка, так что индексы n+0, n+1, n+2... красиво карта с 0, 1, 2...

РЕДАКТИРОВАТЬ 3 : Мартин сохранил еще один байт на последнем этапе процесса. Приятно!

Линн
источник
6

Пиф, 48 43

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

Тестирование

Требуется заполнение пробелами в прямоугольник.

Я не думаю, что это лучший подход, но в основном он записывает среднее значение индекса в строку, на которую указывает верхнее или нижнее значение. Ну, я думаю, у меня было достаточно времени, чтобы поиграть в гольф из большинства очевидных вещей, которые я видел. :П

FryAmTheEggman
источник
4

JavaScript (ES7), 115

Анонимная функция. Используя строки шаблона, есть новая строка, которая важна и включена в число байтов.

Требование: средняя строка ввода не может быть короче первой или последней. Это требование удовлетворяется, когда ввод дополнен пробелами для формирования прямоугольника.

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 версия 117 с использованием .map вместо понимания массива

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

Меньше гольфа

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

Тестовый фрагмент

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
источник
Поздравляю с тем, что первым решил обе проблемы. :)
Мартин Эндер
3

Haskell, 125 106 103 байта

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]

Требуется заполнение пробелами до полного прямоугольника.

Пример использования: f " 1 3 24\n0 1 2 7 8 \n57 6 8 "-> "1878-02-08".

Как это устроено:

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

Тестовые случаи .

Михал Перлаковский
источник
1

Perl, 154 байта

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}

Разоблаченный и объясненный

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
источник
0

JavaScript (ES6), 131 байт

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

объяснение

Требуется, чтобы ввод был дополнен пробелами для формирования прямоугольника.

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

Контрольная работа

user81655
источник
0

Powershell, 119 байт

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

Неуправляемый тестовый скрипт:

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

Выход:

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
источник
0

Желе , 38 байт

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

Попробуйте онлайн!

Помощник только там, чтобы облегчить ввод; это на самом деле полная программа. Обязательно позаботьтесь о :

  • Первая и последняя строки ( '''), а также строки рядом с ними (пусто, там для наглядности).
    • Фактический формат ввода не имеет второй и предпоследней пустых строк, и строка начинается и заканчивается непосредственно рядом с кавычками, без новой строки между ними, например:
      '' '1 3 24
      0 1 2 7 8 
      57 6 8 '' '
      Вы можете оставить нижний колонтитул во время использования этого формата. Это действительно многострочная строка Python, и для некоторых входных данных необходимы кавычки.
  • Дополните ввод пробелами! Любой правильный вывод без правильно дополненного ввода является полностью случайным и не одобрен мной.
Эрик Outgolfer
источник