Срок годности моего молока истек?


98

Оу, чувак, эта дата истечения срока не записывает месяцы с буквами! Я не могу сказать, истекает ли это 10 марта или 3 октября ... Подождите, нет, неважно, год говорит о 2012. (alley-ой наполовину использованный кирпич сыра в мусорное ведро как профессионал)

Итак, давайте на минутку предположим, что вы слишком заняты, чтобы попытаться выяснить, когда должен закончиться срок действия этой банки маринары. Вы просто хотите версию Cliff Notes: насколько вероятно, что она просрочена? Давайте напишем некоторый код!

Вы знаете, что производители печатают дату в виде упорядоченной тройки целых чисел в одном из трех форматов:

YEAR  MONTH DAY
MONTH DAY   YEAR
DAY   MONTH YEAR

И вы знаете, что некоторые даты можно интерпретировать только одним или двумя способами, а не всеми тремя: 55-й год 55-11-5должен быть годом, означающим, что срок действия этой конкретной коробки Twinkies истек 5 ноября 1955 года. Год иногда дается в четыре цифры и не два, которые могут исключить некоторые варианты. Когда это две цифры, однако, 50..99 означает 1950..1999, а 0..49 означает 2000..2049.

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

Массив целых чисел будет [Int]типом вашего языка длины три, если он является аргументом функции, и задан как целые, разделенные пробелом или пробелом (вы можете выбрать), если он используется в качестве входных данных для STDIN для полная программа. *

«Сегодняшняя дата» может быть текущей фактической датой, полученной с помощью функции date, или датой, указанной в дополнительном аргументе функции или дополнительном параметре в STDIN. Это могут быть секунды эпохи Unix, другая тройка год-месяц-день, введенная одним из трех указанных выше способов, или другой более удобный способ.

Давайте иметь несколько примеров! Ввод даты окончания срока действия будет выполнен в стиле, разделенном тире, и для приведенных ниже примеров предполагается, что сегодняшняя дата - 5 июля 2006 года.

  • 14-12-14- Обе действительные интерпретации для этого (DMY и YMD) эквивалентны, 14 декабря 2014 года. Результат - 100, потому что этот продукт определенно все еще хорош.
  • 8-2-2006- Последний номер, конечно же, год, поскольку он состоит из четырех цифр. Это может быть 8 февраля (истек) или 2 августа (все еще хорошо). Выход 50 .
  • 6-7-5- Это может быть что угодно! Интерпретация «5 июля 2006 г.» все еще хороша (только на один день), но остальные два - в 2005 г. и должны быть отброшены как можно быстрее. Выход 33 .
  • 6-5-7- Здесь две из трех интерпретаций безопасны. Вы можете округлить десятичную дробь вверх или вниз, так что с 66 или 67 все в порядке.
  • 12-31-99- Хорошо, этот однозначно относится к рубежу веков (годы с 50 по 99 - 19XX, а 31 не может быть месяцем). Большой жирный 0 , и вы действительно должны почистить холодильник чаще.

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

Нет веб-запросов или стандартных лазеек. Библиотеки обработки даты разрешены. Это код гольф: пусть победит самая короткая программа.

* Если вы используете brainfuck или какой-либо подобный язык с недостатками типа данных, вы можете предположить, что значения ASCII первых трех символов на входе являются целыми числами для даты. Конечно, это исключает логику четырехзначного года, но я думаю, что мы были бы слишком изумлены, увидев решение этой проблемы в Brainfuck, чтобы подсказать вам за это.


39
Ммм ... текущий год 2014, а не 2006. Ваше молоко в лучшем случае прошло восемь лет.
Джон Дворак

11
@JanDvorak Я просто не хотел очень стараться создавать содержательные примеры, поэтому я подправил сегодняшнюю дату, чтобы упростить ее.
алгоритм

7
@ Dgrin91 пофиг, я все равно их съем: D
aditsu

6
В Австралии срок годности молока истекает примерно за неделю до даты употребления
gnibbler

5
Вы должны добавить тест с 00, так как это не может быть официальным днем ​​или месяцем.
MtnViewMark

Ответы:


5

k4 (90) (88) (87) (82)

{100*(+/~d<x)%3-+/^d:{"D"$"."/:$|z,y,x+(x<100)*100*19+x<50}.'y@/:3 3#.:'$21020101}

Вызовите xиз .z.D(встроенного) для сравнения с сегодняшним днем ​​или литералом даты по вашему выбору в противном случае:

  f:{100*(+/~d<x)%3-+/^d:{"D"$"."/:$|z,y,x+(x<100)*100*19+x<50}.'y@/:3 3#.:'$21020101}
  .z.D f'(14 12 14;8 2 2006;6 7 5;6 5 7;12 31 99)
100 0 0 0 0f
  2006.07.05 f'(14 12 14;8 2 2006;6 7 5;6 5 7;12 31 99)
100 50 33.33333 66.66667 0

По сути, это порт Python-решения @ Alex-l, в который добавлено несколько разных хитростей:

  • Инструкции перестановки закодированы в строку, чтобы сохранить пару символов.
  • Условная логика (ab) использует истину как целое число (но не так, как в решении Python).
  • Тест достоверности немного отличается - k4 / q с радостью проанализирует любую строку в любом типе данных; он просто возвращает ноль, если не может понять это. Таким образом, я возвращаю список дат из внутренней функции, который может быть или не быть нулевым.
  • Окончательный результат получается из проверки, сколько из возможных интерпретаций даты равно нулю, а сколько меньше даты сравнения; здесь важно, чтобы нулевая дата считалась меньше любой другой даты.

1
Вы можете сохранить символ, удалив последние 0 из "012201210", так как он #принимает его элементы циклически. На самом деле, вы можете сэкономить на секунду CHAR таким образом, меняя последние два случая: 3 3#.:'"0122102".
алгоритмический

Побрил еще один символ, поменяв местами аргументы внутреннего функционала, сохранив парены (но добавив обратный). Может ли кто-нибудь помочь мне сохранить еще два символа? APL бьет меня!
Аарон Дэвис

Побрил еще пять, переписав математику в конце. Вернуться в лидеры!
Аарон Дэвис

И если я наклониться писать серьезно нефункциональные код, я могу бриться еще один байт, загрязняя глобальное пространство имен: {c*(+/~d<x)%3-+/^d:{"D"$"."/:$|z,y,x+(c*19+x<50)*x<c::100}.'y@/:3 3#.:'$21020101}.
Аарон Дэвис

14

Рубин, 115 знаков

f=->a,t{[a,a.rotate(~s=r=0),a.reverse].map{|x,*y|(t>Time.gm(x<100?x+2e3-100*x/=50:x,*y)||r+=100
s+=1)rescue p}
r/s}

Это определяет функцию, fкоторая принимает два аргумента: массив, содержащий входные данные, и «сегодняшнюю» дату.

Примеры:

f[[14,12,14], Time.new]
100
f[[8,2,2006], Time.new]
0
f[[8,2,2006], Time.new(2006, 7, 5)]
50
f[[6,7,5], Time.new(2006, 7, 5)]
33

12

Python 2.7 - 172

Я использую модуль datetime для валидности и сравнения дат. Если dateне удается сделать правильное время и дату из входных данных, они повышаются ValueError. Этот способ sпредставляет собой сумму дат с истекшим сроком действия и tобщее количество действительных дат. Я пользуюсь тем, что True == 1для целей добавления и индексации в Python. Я также сохраняю персонажа, используя 25 * (76,80) вместо (1900,2000).

Обратите внимание, что строки на втором уровне отступа используют символ табуляции, а не 2 пробела.

def f(e,c,s=0,t=3):
 for Y,M,D in(0,1,2),(2,0,1),(2,1,0):
  y=e[Y]
  try:s+=date(y+25*[[76,80][y<50],0][y>99],e[M],e[D])>=c
  except:t-=1
 return 100*s/t

Добавьте это в конец, чтобы проверить:

examples = [[14,12,14],[8,2,2006],[6,7,5],[6,5,7],[12,31,99]]
for e in examples:
 print f(e, date(2006,7,5))

10

PowerShell, 183 173 168

[int](100*(($d=@(($a,$b,$c=$args[0]),($c,$a,$b),($c,$b,$a)|%{$_[0]+=1900*($_[0]-le99)+100*($_[0]-le49)
.{date($_-join'-')}2>$x}|sort -u))-ge(date)+'-1').Count/$d.Count)
  • Ввод как int[]через параметр, например

    PS> ./milk.ps1 5,6,7
    
  • Сообщения об ошибках приглушаются через try/ catch, пока я не знаю, разрешен ли вывод на stderr или нет.
  • Использование +"-1"даты, которая интерпретируется как .AddDays(-1)смещение текущей даты на один день, чтобы мы могли сравнить ее со вчерашним днем ​​(а не только с сегодняшним днем). Это решает проблему, заключающуюся в том, что мы получаем дату с 0:00 как время, но нужно сравнить с датой со временем с сегодняшнего дня.
  • К настоящему времени
  • Использование нового трюка для исправления ошибок, который немного короче

6

R 269

Я ожидал, что это будет легко в R, но годы с одной цифрой были довольно большим кривая. Я чувствую, что это может быть намного лучше, чем есть.

lubridateэто пакет от CRAN, вам может потребоваться его установка install.packages("lubridate").

require(lubridate)
f = function(d){
d=sapply(d,function(l)if(nchar(l)==1)sprintf("%02d",l)else l)
d=paste0(d,collapse="-")
t=ymd(Sys.Date())
s=na.omit(c(ymd(d),mdy(d),dmy(d)))
s=lapply(s,function(d){
if(year(d)>2049){year(d)=year(d)-100;d}
else d})
sum(s>t)/length(s)}

Использование: f(c(d1,d2,d3))где c(d1,d2,d3)находится вектор целых чисел.

например, f(c(6,10,14))возвращается 0.3333333.

lubridateПакет имеет ряд функций - оболочек для разбора дат в различных порядках. Я использую их, чтобы увидеть, какие форматы дают действительные даты, выбрасывать недействительные, а затем посмотреть, какие еще не произошли.


6

Mathematica, 163 153 164 байта

( редактировать: фиксированные даты вне диапазона 1950 - 2049)

f=100.Count[#,x_/;x<1]/Length@#&[DateDifference[#,Date[]]&/@Cases[{If[#<100,Mod[#+50,100]+1950,#],##2}&@@@{{##},{#3,#2,#},{#3,#,#2}}&@@#,d_/;DateList@d~Take~3==d]]&

Это определяет функцию, которую вы можете вызвать как

f[{6,7,5}]

В настоящее время процент не округляется (в ожидании разъяснения ОП).

Вот немного длинное объяснение , которое должно быть понятно без знания Mathematica (заметим , что &делает все от него осталось анонимная функция, параметры которой называют #, #2, #3...):

{{##},{#3,#2,#},{#3,#,#2}}&

Это определяет функцию, которая превращает 3 параметра a,b,cв 3 списка {{a,b,c},{c,b,a},{c,a,b}. Обратите внимание, что ##это просто последовательность всех параметров.

{{##},{#3,#2,#},{#3,#,#2}}&@@#

Применительно к дате истечения срока действия, это дает список {y,m,d}для каждой из трех возможных перестановок.

{If[#<100,Mod[#+50,100]+1950,#],##2}&

Это анонимная функция, которая принимает три параметра a,b,cи возвращает список из трех, где первый был преобразован в год согласно заданным правилам: числа между 50и 99(по модулю 100) превращаются в год 20-го века, числа между 0и 49( по модулю 100) превращены в год 21 века, все остальные остались вместе. Здесь, ##2представляет собой последовательность параметров , начиная со второго, то есть b,c.

{If[#<100,Mod[#+50,100]+1950,#],##2}&@@@{{##},{#3,#2,#},{#3,#,#2}}&@@#

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

Cases[canonicalDates,d_/;DateList@d~Take~3==d]

Это отфильтровывает неверные интерпретации. DateList@dделает полное {y,m,d,h,m,s}представление из различных форматов даты. Он будет интерпретировать списки в том же порядке, но выгода заключается в том, что вы можете передавать ему такие вещи, как {8,2,2006}в этом случае он будет вычислять 8 years + 2 months + 2006 days. Поэтому мы проверяем, что первые три элемента возвращенного списка идентичны входным данным (что может произойти, только если месяц и день находятся в соответствующих диапазонах).

Чтобы сократить следующие строки, я буду ссылаться на результат этого выражения validDatesс этого момента :

DateDifference[#,Date[]]&

Другая анонимная функция, которая принимает дату и возвращает разницу в днях до сегодняшнего дня (получена из Date[]).

DateDifference[#,Date[]]&/@validDates

Сопоставьте это с действительными интерпретациями даты.

100.Count[#,x_/;x<1]/Length@#&

Еще одна анонимная функция, которая, учитывая list ( #), возвращает процент неположительных чисел в этом списке. Это .не умножение, а просто десятичная цифра, чтобы избежать рациональных чисел в результате (вы получите такие вещи, как 100/3вместо 33.333- я на самом деле не знаю, если это проблема).

100.Count[#,x_/;x<1]/Length@#&[DateDifference[#,Date[]]&/@validDates]

Применительно к списку различий дат это дает нам часть интерпретаций, которые еще не истекли.


Я думаю, что вы неправильно конвертируете годы, например, 2999 или 2099 в 1999.
Ventero

@ Вентеро, это правда. Я вроде предположил, что мы имеем дело только с 1950–2049 годами (и их версиями с 1 или 2 цифрами), но, перечитывая проблему, об этом ничего не сказано.
Мартин Эндер

@Ventero исправлено (но вы уже сильно меня избили;))
Мартин Эндер

Я удивлен, увидев, что у вас есть аккаунт на Mathematica, но вы не опубликовали ни одного вопроса или ответа. Что-то сдерживает тебя?
Мистер Волшебник

@ Mr.Wizard извини, совсем забыла тебе ответить. Вопросы: до сих пор каждая проблема, которую я имел, могла быть решена с помощью поиска в Google / других вопросов SE. Ответы: Я не знаю ... Я предполагаю , что я не считаю себя , что опытным , когда речь заходит об использовании Mathematica продуктивно ... Я только использовать его для быстрых фрагментов здесь и там (и код для гольфа). Кроме того, я думаю, чтобы отвечать на вопросы, мне нужно будет активно смотреть новые, чтобы увидеть, на что я могу ответить, и в настоящее время все мое время SE отводится на PPCG. ;) Если вы хотите, чтобы я убедил меня в обратном, не стесняйтесь делать это в чате! :)
Мартин Эндер

4

JavaScript (E6) 159 164 172

Edit Спасибо nderscore за подсказки и за то, что подтолкнул меня к мысли снова. Реорганизован D, избегая параметров и сокращая некоторые символы.

Редактировать 2 Еще один трюк от nderscore, 2 функции объединены в 1. Затем две круглые скобки убрали объединение выражений через запятую в одно. Читаемость около 0. Sidenote: Не округление может спасти еще 2 символа (| 0).

F=(a,t)=>t?100*(3-((i=F([y,m,d]=a))<t)-((j=F([m,d,y]=a))<t)-((k=F([d,m]=a))<t))/(3-!i-!j-!k)|0:(q=new Date(y<50?y+2e3:y,--m,d)).getMonth()==m&q.getDate()==d&&q

Консоль Test In FireFox

;[[14,12,14],[8,2,2006],[6,7,5],[6,5,7],[12,31,99]]
.map(x=>x + ' ' + F(x, new Date(2006,6,5)))

Выход:

["14,12,14 100", "8,2,2006 50", "6,7,5 33", "6,5,7 66", "12,31,99 0"]

Ungolfed

Примечание: функция D пытается создать дату с указанным годом, месяцем, днем, но возвращает false, если созданная дата не соответствует назначению (! = День или месяц)

F=(d,t)=>
(
  D=(y,m,d)=>(
    q=new Date(y<50?y+2000:y, --m, d), // decr m as javascript (like java) counts months starting at 0
    q.getMonth() == m & q.getDate() == d && q
  ),
  [a,b,c] = d, 
  x=D(...d), // three ways of express the date ...
  y=D(c,a,b),
  z=D(c,b,a),
  100 * (3-(x<t)-(y<t)-(z<t)) / (3-!x-!y-!z) | 0  
)   

@nderscore ОК для изменений в D, ошибка синтаксиса для других. Но все равно сохранил еще больше
edc65

Weird. Что-то должно было случиться, когда я вставил это в комментарий. Ваши последние оптимизации делают его неактуальным, хотя :)
nderscore

1
Поместив это в пасту, я больше не доверяю комментариям SE: (-3) pastie.org/private/6bemdweyndcaiseay70kia
nderscore

4

C # в LINQPad - 446 408 272 байта

Третье редактирование: Спасибо Ле Канар Фу за указание, что DateTime.Today является правильным, а не DateTime.Now. Второе редактирование: спасибо VisualMelon за это умное решение!

void g(int[]d){var p=".";int a=d[2],b=d[1],e=d[0],y=a+(a<100?a>49?1900:2000:0),q=0,s=0;DateTime c;Action<string>z=x=>{if(DateTime.TryParse(x,out c)){s++;if(c>=DateTime.Today)q+=100;}};z(e+p+b+p+y);z(b+p+e+p+y);z(a+p+b+p+(e<100?‌​e>49?1900+e:2000+e:e));(q/(s>0?s:1)).Dump();}

Изменить: Спасибо podiluska и edc65 за помощь в создании кода! Я также заметил, что мое решение не было правильным, если годовой ввод был 4 байта, поэтому я включил исправление для этой проблемы. Оценка для этого решения составляет 408 байт.

Несмотря на то, что я не бью ни одного из предыдущих ответов, я все же хотел поделиться своим решением C #. Любая помощь / предложения приветствуются! ;)

void g(int[]d){var q=new List<DateTime>();var p=".";int s=0,a=d[2],b=d[1],e=d[0],y=0;var c=new DateTime();y=(a<100)?(a>49)?1900+a:2000+a:a;if(DateTime.TryParse(e+p+b+p+y,out c)){q.Add(c);s++;}if(DateTime.TryParse(b+p+e+p+y,out c)){q.Add(c);s++;}y=(e<100)?(e>49)?1900+e:2000+e:e;if(DateTime.TryParse(a+p+b+p+y,out c)){q.Add(c);s++;}q=q.Where(i=>i>=DateTime.Now).ToList();if(s==0){s=1;}(q.Count*100/s).Dump();}

Отформатированная и разглаженная версия:

void g(int[] d)
    {
        var q = new List<DateTime>();
        var p = ".";
        int s = 0, a = d[2],b = d[1],e = d[0], y=0;
        var c = new DateTime();
        y = (a < 100) ?((a > 49) ? 1900 + a : 2000 + a) : a;

        if (DateTime.TryParse(e + p + b + p + y, out c))
        {
            q.Add(c);
            s++;
        }
        if (DateTime.TryParse(b + p + e + p + y, out c))
        {
            q.Add(c);
            s++;
        }
        y = (e < 100) ? ((e > 49) ? 1900 + e : 2000 + e) : e;

        if (DateTime.TryParse(a + p + b + p + y, out c))
        {
            q.Add(c);
            s++;
        }
        q = q.Where(i => i >= DateTime.Now).ToList();
        if (s == 0)
        {
            s = 1;
        }
        (q.Count*100/s).Dump();
    }

Я попытался создать решение, при котором «DateTime.TryParse» -Part не повторяется, как в этом решении, но оно было на 21 байт длиннее.

Решение без повторения «DateTime.TryParse»: 467 байт

void g(int[]d){var q=new List<DateTime>();int s=0;int a=d[2];int b=d[1];int e=d[0];int y=0;if(a<100){if(a>49){y=1900+a;}else{y=2000+a;}}if(z(e,b,y,q)){s++;}if(z(b,e,y,q)){s++;}if(e<100){if(e>49){y=1900+e;}else{y=2000+e;}}if(z(a,b,y,q)){s++;}q=q.Where(i=>i>=DateTime.Now).ToList();if(s==0){s=1;}(q.Count*100/s).Dump();}bool z(int a,int b,int d,List<DateTime> q){var c=new DateTime();var p=".";if(DateTime.TryParse(a+p+b+p+d,out c)){q.Add(c);return true;}return false;}

Безголовая версия:

private void g(int[] d)
    {
        var q = new List<DateTime>();
        int s = 0;
        int a = d[2];
        int b = d[1];
        int e = d[0];
        int y = 0;
        if (a < 100)
        {
            if (a > 49)
            {
                y = 1900 + a;
            }
            else
            {
                y = 2000 + a;
            }
        }
        if (z(e, b, y, q))
        {
            s++;
        }
        if (z(b, e, y, q))
        {
            s++;
        }
        if (e < 100)
        {
            if (e > 49)
            {
                y = 1900 + e;
            }
            else
            {
                y = 2000 + e;
            }
        }
        if (z(a, b, y, q))
        {
            s++;
        }
        q = q.Where(i => i >= DateTime.Now).ToList();
        if (s == 0)
        {
            s = 1;
        }
        (q.Count*100/s).Dump();
    }

    private bool z(int a, int b, int d, List<DateTime> q)
    {
        var c = new DateTime();
        string p = ".";
        if (DateTime.TryParse(a + p + b + p + d, out c))
        {
            q.Add(c);
            return true;
        }
        return false;
    }

2
int s=0;int a=d[2];int b=d[1];int e=d[0];->int s=0,a=d[2],b=d[1],e=d[0];
Подилуска

2
предложение: используйте троичный (? :) когда это возможно вместо if / else
edc65

1
@ThomasW. Я не думаю, что поскольку у у 2 разных значения, одно время зависит от a, другое - от e. Спасибо, в любом случае!
Цавиньо

1
Удаление DateTime.TryParseвызовов было моим первым инстинктом, заменил его лямбда-выражением, которое также возвращает значение в q. Также выполнил некоторые другие шаги ( pastebin ), чтобы получить 328 знаков:void g(int[]d){var q=new List<DateTime>();var p=".";int a=d[2],b=d[1],e=d[0],y;DateTime c;y=(a<100)?(a>49)?1900+a:2000+a:a;Action<string>z=(x)=>{if(DateTime.TryParse(x,out c))q.Add(c);};z(e+p+b+p+y);z(b+p+e+p+y);y=(e<100)?(e>49)?1900+e:2000+e:e;z(a+p+b+p+y);(q.Where(i=>i>=DateTime.Now).Count()*100/(q.Any()?q.Count:1)).Dump();}
VisualMelon

1
@VisualMelon Wow, вы действительно хороши в игре в код! Я никогда не видел Action<string>раньше, поэтому я мог кое-что узнать от вас;) Я смог получить ваш ответ до 318 символов, заменив q.Where(i=>i>=DateTime.Now).Countна q.Count(i=>i>=DateTime.Now. Я также убрал квадратные скобки, xчтобы сохранить еще 2 символа!
Цавиньо

3

Haskell, 171 165 знаков

l=length
r y|y<100=(y+50)`mod`100+1950|y>0=y
q d m y z|d<32&&m<13&&d*m>0=(r y,m,d):z|1<3=z
v(a,b,c)=q c b a$q b a c$q a b c[]
t%d=(l$filter(>t)(v d))*100`div`l(v d)

Имя функции есть %. Запустите тестовую дату в виде кортежа в каноническом (y, m, d) порядке с указанием фактического года и отметки на коробке в виде кортежа из трех чисел:

λ: (2006,6,5)%(14,12,14)
100

λ: (2006,6,5)%(8,2,2006)
50

λ: (2006,6,5)%(6,7,5)
33

λ: (2006,6,5)%(6,5,7)
66

λ: (2006,6,5)%(12,31,99)
0

λ: (2006,6,5)%(0,1,7)
0

2

Эрланг, 146

f([A,B,C]=U,N)->F=[T||T<-[{(Y+50)rem 100+1950,M,D}||[Y,M,D]<-[U,[C,A,B],[C,B,A]]],calendar:valid_date(T)],100*length([1||T<-F,T>=N])div length(F).

Тестовая функция будет:

t() ->
    0 = f([12,31,99],{2006,6,5}),
    66 = f([6,5,7],{2006,6,5}),
    33 = f([6,7,5],{2006,6,5}),
    100 = f([14,12,14],{2006,6,5}),
    50 = f([8,2,2006],{2006,6,5}),
    100 = f([29,2,2],{2006,6,5}).

Ungolfed

f([A,B,C]=U,Today)->
    Perms = [U,[C,A,B],[C,B,A]],
    WithYears = [{(Y+50) rem 100+1950,M,D} || [Y,M,D] <- Perms],
    ValidDates = [T || T <- WithYears, calendar:valid_date(T)],
    100*length([1 || T <- ValidDates, T >= Today]) div length(ValidDates).

Это решение основано на списках. Он заимствует трюк по модулю на год из решения Haskell. Он также используется calendar:valid_date/1для обработки невозможных дат из-за количества дней в данном месяце (например, «29-2-2» может быть только в формате YMD). Кроме того, Today в date()формате Erlang (кортеж YMD).


2

APL (85)

При этом используются некоторые новые функции Dyalog APL 14, но нет внешних библиотек. Для разнообразия работает на TryAPL .

{100×(+/÷⍴)⍺≤{(3/100)⊥⍵+(99≥⊃⍵)×3↑1900+100×50>⊃⍵}¨Z/⍨{∧/12 31≥1↓⍵}¨Z←(⊂⌽⍵),(⊂2⌽⍵),⊂⍵}

Это функция, которая принимает массив из 3 элементов в качестве аргумента right side ( ), а дату, с которой сравнивается как аргумент left side ( ), - как целое число YYYYMMDDформата. Т.е. дата 2014-07-09представляется в виде числа 20140709.

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

      20060705 {100×(+/÷⍴)⍺≤{(3/100)⊥⍵+(99≥⊃⍵)×3↑1900+100×50>⊃⍵}¨Z/⍨{∧/12 31≥1↓⍵}¨Z←(⊂⌽⍵),(⊂2⌽⍵),⊂⍵} 14 12 14
100
      20060705 {100×(+/÷⍴)⍺≤{(3/100)⊥⍵+(99≥⊃⍵)×3↑1900+100×50>⊃⍵}¨Z/⍨{∧/12 31≥1↓⍵}¨Z←(⊂⌽⍵),(⊂2⌽⍵),⊂⍵} 8 2 2006
50
      20060705 {100×(+/÷⍴)⍺≤{(3/100)⊥⍵+(99≥⊃⍵)×3↑1900+100×50>⊃⍵}¨Z/⍨{∧/12 31≥1↓⍵}¨Z←(⊂⌽⍵),(⊂2⌽⍵),⊂⍵} 6 7 5
33.3333
      20060705 {100×(+/÷⍴)⍺≤{(3/100)⊥⍵+(99≥⊃⍵)×3↑1900+100×50>⊃⍵}¨Z/⍨{∧/12 31≥1↓⍵}¨Z←(⊂⌽⍵),(⊂2⌽⍵),⊂⍵} 12 31 99
0

Объяснение:

  • Z←(⊂⌽⍵),(⊂2⌽⍵),⊂⍵: преобразовать указанную дату в формат YMD, щелкнув (⊂⌽⍵), повернув ее влево на 2 (⊂2⌽⍵)или просто ничего не делая ⊂⍵. По крайней мере, одна из них теперь является правильной датой в формате YMD, возможно, больше, чем одна, если дата неоднозначна.
  • {∧/12 31≥1↓⍵}¨Z: test, если каждая дата действительна: год (первый элемент) отбрасывается, а затем месяц должен быть не выше 12, а день не должен быть выше 31.
  • Z/⍨: отфильтровать действительные даты от Z.
  • {... : на каждую действительную дату:
    • ⍵+(99≥⊃⍵)×3↑1900+100×50>⊃⍵: если год не выше 99, добавьте 1900, затем 100, если год меньше 50.
    • (3/100)⊥: расшифруйте его так, как если бы это был набор чисел base-100. (Год больше 100, но это не имеет значения, поскольку это первый элемент.) Это дает число для каждой действительной даты в том же формате, что и левый аргумент.
  • ⍺≤: для каждой даты посмотрите, не меньше ли она чем . Это даст двоичный вектор, где 1 означает, OKа 0 означает spoiled.
  • 100×(+/÷⍴): разделите сумму двоичного вектора на его длину и умножьте на 100.

Сохраните 7 байтов (и разбейте K с хорошим запасом) с помощью {100×(+/÷⍴)⍺≤((3/100)⊥⊢+(99≥⊃)×3↑1900+100×50>⊃)¨Z/⍨{∧/12 31≥1↓⍵}¨Z←(⌽⍵)(2⌽⍵)⍵}
прядей и

0

Java: 349 символов (3 без пробелов)

int e(int[]n,Date t){int a=n[0],b=n[1],c=n[2];Date[]d=new Date[3];if(b<13&&c<32)d[0]=new Date((a<50?100:(a>100?-1900:0))+a,b-1,c);if(b<13&&a<32)d[1]=new Date((c<50?100:(c>100?-1900:0))+c,b-1,a);if(a<13&&b<32)d[2]=new Date((c<50?100:(c>100?-1900:0))+c,a-1,b);int v=0,g=0;for(int i=0;i<3;i++)if(d[i]!=null){if(!d[i].before(t))g++;v++;}return 100*g/v;}

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

import java.util.*;
class i{

   int e(int[]n,Date t){
      int a=n[0],b=n[1],c=n[2];
      Date[]d=new Date[3];
      if(b<13&&c<32)d[0]=new Date((a<50?100:(a>100?-1900:0))+a,b-1,c);
      if(b<13&&a<32)d[1]=new Date((c<50?100:(c>100?-1900:0))+c,b-1,a);
      if(a<13&&b<32)d[2]=new Date((c<50?100:(c>100?-1900:0))+c,a-1,b);
      int v=0,g=0;
      for(int i=0;i<3;i++)
         if(d[i]!=null){
            if(!d[i].before(t))
               g++;
            v++;
         }
      return 100*g/v;}

   public static void main(String[] args){
      int[]i=new int[3];
      for(int k=0;k<3;k++)
         i[k] = Integer.parseInt(args[k]);
      int j = new i().e(i,new Date());
      System.out.println(j+"%");
   }   
}

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


1
Вы должны принять в int[]качестве аргумента, а не три intс.
Джои

хорошо, я исправил это.
shieldgenerator7

0

C # 287 байт

namespace System{class E{static float a,o,l;void M(int[]i){int d=i[0],m=i[1],y=i[2],t;if(l<3)try{if(l==1){t=y;y=d;d=t;}if(l++==0){t=d;d=m;m=t;}if(y<100&&(y+=1900)<1950)y+=100;o+=new DateTime(y,m,d)>=DateTime.Today?1:0;a++;if(l<3)i[9]=9;}catch{M(i);throw;}Console.Write(o/a);}}}

Первый раз играю в гольф, ищу советы. В частности, удаление байтов из-за пространства имен.

Злоупотребление фактом, что требуется только функция, а не фактическая программа. Кроме того, функция всегда приводит к необработанному исключению.

Ungolfed

namespace System {
    class E {
        static float a, o, l;
        void M(int[] i) {
            int d = i[0], m = i[1], y = i[2], t;
            if (l < 3)
                try {
                    if (l == 1) { 
                        t = y; y = d; d = t; 
                    } 
                    if (l++ == 0) { 
                        t = d; d = m; m = t; 
                    } 
                    if (y < 100 && (y += 1900) < 1950)
                        y += 100; 
                    o += new DateTime(y, m, d) >= DateTime.Today ? 1 : 0; // # not expired
                    a++; // # valid dates
                    if (l < 3)
                        i[9] = 9; // throw new Exception()
                } 
                catch { 
                    M(i);
                    throw; // fail after the first Console.Write()
                } 
            Console.Write(o / a); 
        } 
    } 
}

0

Математика , 118

Используя код m.buettner в качестве отправной точки, у меня есть несколько улучшений:

⌊100Mean@UnitStep@Cases[DateDifference@{If[#<100,Mod[#+50,100]+1950,#],##2}&@@@{#,RotateRight@#,Reverse@#},_Integer]⌋&

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

@algorithmshark Спасибо. Я не знаю, как я это пропустил. Обновление ...
Mr.Wizard
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.