Meu leite expirou?

98

Aww, cara, esse prazo de validade não escreve os meses com letras! Não sei dizer se está expirando em 10 de março ou 3 de outubro ... Espere, não, não importa, o ano diz 2012. (o beco-oops tijolo de queijo meio usado no lixo pode ser um profissional)

Então, vamos supor por um momento que você está muito ocupado para tentar pensar quando esse pote de marinara deve expirar. Você quer apenas a versão do Cliff Notes: qual a probabilidade de atraso? Vamos escrever um código!

Você sabe que os fabricantes imprimem a data como um triplo ordenado de números inteiros, em um dos três formatos:

YEAR  MONTH DAY
MONTH DAY   YEAR
DAY   MONTH YEAR

E você sabe que algumas datas só podem ser interpretadas de uma ou duas maneiras, e não as três: a 55 em 55-11-5tem que ser um ano, significando que essa caixa específica de Twinkies expirou em 5 de novembro de 1955. Às vezes, o ano é dado em quatro dígitos e não dois, o que pode excluir algumas opções. Quando tem dois dígitos, 50..99 significa 1950..1999 e 0..49 significa 2000..2049.

Seu trabalho é escrever um programa ou função que utilize uma matriz de números inteiros que seja uma data válida em pelo menos uma das interpretações acima e dê uma chance percentual de que ainda seja bom. A chance percentual é simplesmente a porcentagem de interpretações válidas da data que estão na data posterior ou posterior à data de hoje.

A matriz de números inteiros será o [Int]tipo de comprimento três da sua linguagem, se for um argumento para uma função, e fornecida como inteiros separados por traço, barra ou espaço (você escolhe), se usados ​​como entrada em STDIN para um programa completo. *

"Data de hoje" pode ser a data real de hoje, obtida através de uma função de data, ou a data fornecida em um argumento extra para funcionar ou paramater extra no STDIN. Pode ser no Unix, época segundos, outro triplo ano-mês-dia inserido de uma das três maneiras acima, ou de outra maneira mais conveniente.

Vamos dar alguns exemplos! A entrada da data de validade será no estilo separado por traço e assuma os exemplos abaixo que a data de hoje é 5 de julho de 2006.

  • 14-12-14- Ambas as interpretações válidas para isso (DMY e YMD) são equivalentes, 14 de dezembro de 2014. A saída é 100 porque este produto ainda é definitivamente bom.
  • 8-2-2006- O último número é um ano, com certeza, uma vez que possui quatro dígitos. Pode ser 8 de fevereiro (expirado) ou 2 de agosto (ainda válido). A saída é 50 .
  • 6-7-5- Isso pode ser qualquer coisa! A interpretação "5 de julho de 2006" ainda é boa (apenas por um dia), mas os dois restantes são ambos em 2005 e devem ser lançados o mais rápido possível. A saída é 33 .
  • 6-5-7- Aqui, duas em cada três interpretações são seguras. Você pode arredondar seu decimal para cima ou para baixo, para que 66 ou 67 fiquem bem.
  • 12-31-99- Tudo bem, este é inequivocamente da virada do século (anos de 50 a 99 são 19XX e 31 não pode ser um mês). Um 0 grande e gordo , e você realmente deve limpar sua geladeira com mais frequência.

Você pode assumir com segurança que qualquer entrada que não atenda aos padrões acima não tem acesso às regras de saída acima.

Sem solicitações da Web ou brechas padrão. Bibliotecas de manipulação de datas são permitidas. Este é o código golf: que o programa mais curto vença.

* Se você estiver usando brainfuck ou algum idioma com deficiência de tipo de dados similar, poderá assumir que os valores ASCII dos três primeiros caracteres de entrada são os números inteiros da data. Isso exclui a lógica dos quatro dígitos do ano, com certeza, mas acho que ficaríamos muito surpresos ao ver uma solução para isso em Brainfuck para menosprezá-lo.

algoritmshark
fonte
39
Umm ... o ano atual é 2014, não 2006. Seu leite já passou oito anos do seu vencimento.
John Dvorak
11
@JanDvorak Eu simplesmente não queria me esforçar muito para construir exemplos significativos, então alterei a data de hoje para facilitar.
algorithmshark
7
@ Dgrin91 não me importo, eu ainda vou comê-los: D
aditsu
6
Na Austrália, o leite expira cerca de uma semana antes da utilização por data
gnibbler
5
Você deve adicionar um teste com um 00, pois esse não pode ser um dia ou mês legal.
MtnViewMark

Respostas:

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}

Invoque com xof .z.D(a builtin) para comparação com hoje ou uma data literal de sua escolha: caso contrário:

  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

Esta é basicamente uma porta da solução Python do @ Alex-l, com alguns truques diversos de golfe adicionados:

  • As instruções de reorganização são codificadas em uma sequência para salvar alguns caracteres.
  • A lógica condicional (ab) usa a verdade como número inteiro (mas de uma maneira diferente da solução Python).
  • O teste de validade é um pouco diferente - o k4 / q analisa com facilidade qualquer sequência em qualquer tipo de dados; ele simplesmente retorna um nulo se não conseguir entendê-lo. Assim, retorno uma lista de datas da função interna, que pode ou não ser nula.
  • O resultado final vem da verificação de quantas interpretações possíveis da data são nulas versus quantas são inferiores à data da comparação; aqui é importante que a data nula seja considerada menor que qualquer outra data.
Aaron Davies
fonte
1
Você pode salvar um caracter removendo o último 0 de "012201210", pois #leva seus itens ciclicamente. Na verdade, você pode salvar um segundo caractere desta forma, trocando os dois últimos casos: 3 3#.:'"0122102".
algorithmshark
Raspou mais um caractere, revertendo argumentos da função interna, salvando os parênteses (mas adicionando um reverso). Alguém pode me ajudar a salvar outros dois caracteres? APL está me batendo!
Aaron Davies
Raspou outros cinco reescrevendo a matemática no final. De volta à liderança!
Aaron Davies
E se eu inclinar-se para escrever seriamente código não-funcional, que pode raspar outro byte por poluir o namespace global: {c*(+/~d<x)%3-+/^d:{"D"$"."/:$|z,y,x+(c*19+x<50)*x<c::100}.'y@/:3 3#.:'$21020101}.
Aaron Davies
14

Ruby, 115 caracteres

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}

Isso define uma função fque recebe dois argumentos: uma matriz que contém a entrada e a data "de hoje".

Exemplos:

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
Ventero
fonte
12

Python 2.7 - 172

Eu uso o módulo datetime para validade e comparação de datas. Se datenão for possível extrair um datetime da entrada, ele será gerado ValueError. Dessa forma, sé a soma das datas não expiradas e to número total de datas válidas. Estou aproveitando o fato de que, True == 1para fins de adição e indexação em Python. Também salvei um personagem usando 25 * (76,80) em vez de (1900,2000).

Observe que as linhas no segundo nível de recuo usam um caractere de tabulação, não 2 espaços.

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

Adicione isso ao final para testar:

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))
Alex L
fonte
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)
  • Entrada como int[]via parâmetro, por exemplo

    PS> ./milk.ps1 5,6,7
    
  • As mensagens de erro são silenciadas por try/ catch, desde que eu não saiba se a saída no stderr é permitida ou não.
  • Usando +"-1"na data, que é interpretada como .AddDays(-1)para alterar a data atual em um dia, para que possamos comparar com ontem (em vez de apenas hoje). Isso resolve o problema de obter uma data com 0:00 como hora, mas precisamos comparar com uma data com hora a partir de hoje.
  • Pesadamente, até agora
  • Usando um novo truque para silenciar erros um pouco mais curtos
Joey
fonte
6

R, 269

Eu esperava que isso fosse fácil no R, mas os anos de um dígito foram uma grande curva. Eu sinto que isso poderia ser muito melhor do que é.

lubridateé um pacote do CRAN, pode ser necessário instalá-lo 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)}

Uso: f(c(d1,d2,d3))onde c(d1,d2,d3)é um vetor de números inteiros.

por exemplo, f(c(6,10,14))retornos 0.3333333.

O lubridatepacote possui uma série de funções de wrapper para analisar datas em diferentes pedidos. Eu os uso para ver quais formatos produzem datas válidas, jogar fora os inválidos e depois ver quais ainda não ocorreram.

shadowtalker
fonte
6

Mathematica, 163 153 164 bytes

( editar: datas fixas fora do intervalo de 1950 a 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]]&

Isso define uma função que você pode chamar como

f[{6,7,5}]

Atualmente, a porcentagem não é arredondada (aguardando o OP esclarecer).

Aqui está uma explicação um pouco demorado que deve ser compreensível sem qualquer conhecimento Mathematica (note que &faz tudo à esquerda dele uma função anônima cujos parâmetros são referidos como #, #2, #3...):

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

Isso define uma função que transforma 3 parâmetros a,b,cem 3 listas {{a,b,c},{c,b,a},{c,a,b}. Observe que ##é apenas uma sequência de todos os parâmetros.

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

Aplicado ao prazo de validade, fornece uma lista de {y,m,d}cada uma das três permutações possíveis.

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

Esta é uma função anônima que aceita três parâmetros a,b,ce retorna uma lista dos três, onde o primeiro foi convertido em um ano de acordo com as regras fornecidas: números entre 50e 99(módulo 100) são transformados em um ano do século 20, números entre 0e 49( módulo 100) são transformados em um ano do século 21, e todos os outros são deixados. Aqui, ##2é uma sequência de parâmetros começando com o segundo, ie b,c.

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

Aplicado a cada um dos três resultados anteriores, isso apenas canoniza os formatos do ano. Vamos chamar isso canonicalDatespara encurtar a seguinte expressão:

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

Isso filtra interpretações inválidas. DateList@dfaz uma {y,m,d,h,m,s}representação completa de vários formatos de data. Ele interpretará as listas na mesma ordem, mas o problema é que você pode passar coisas como {8,2,2006}, nesse caso, será calculado 8 years + 2 months + 2006 days. Portanto, verificamos se os três primeiros elementos da lista retornada são idênticos à entrada (o que só pode acontecer se o mês e o dia estiverem nos intervalos apropriados).

Para encurtar as seguintes linhas, vou me referir ao resultado dessa expressão a partir validDatesde agora:

DateDifference[#,Date[]]&

Outra função anônima que tira uma data e retorna a diferença de dias para hoje (obtida de Date[]).

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

Mapeie isso para as interpretações de data válidas.

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

Ainda outra função anônima que, dada uma lista ( #), retorna a porcentagem de números não positivos nessa lista. Não .é uma multiplicação, mas apenas o dígito decimal, para evitar números racionais como resultado (você obteria coisas como em 100/3vez de 33.333- eu realmente não sei se isso é um problema).

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

Aplicado à lista de diferenças de datas, isso nos dá a fração de interpretações que ainda não expiraram.

Martin Ender
fonte
Eu acho que você incorretamente converter anos como 2999 ou 2099 a 1999.
Ventero
@ Ventero isso é verdade. Eu meio que assumi que estávamos lidando apenas com os anos 1950 - 2049 (e suas versões de 1 ou 2 dígitos), mas relendo o desafio, não há menção a isso.
Martin Ender
@Ventero fixa (mas você já tinha me batido significativamente de qualquer maneira;))
Martin Ender
É uma surpresa ver que você tem uma conta no Mathematica, mas não postou nenhuma pergunta ou resposta. Alguma coisa está te segurando?
precisa saber é o seguinte
@ Mr.Wizard desculpe, esqueci totalmente de responder a você. Perguntas: até agora, todos os problemas que eu tinha poderiam ser resolvidos com pesquisas no Google / outras questões SE. Respostas: Eu não sei ... Eu acho que eu não me vejo como que proficientes quando se trata de usar Mathematica produtivamente ... Eu só usá-lo para trechos rápidos aqui e ali (e golfe código). Além disso, acho que para responder a perguntas, eu teria que assistir ativamente a novas para ver o que posso responder, e atualmente todo o meu tempo de SE é alocado para o PPCG. ;) Se você quiser me convencer do contrário, sinta-se à vontade para fazer isso no chat! :)
Martin Ender
4

JavaScript (E6) 159 164 172

Editar Obrigado ao nderscore pelas dicas e por me fazer pensar novamente. Reorganizei D evitando parâmetros e cortando alguns caracteres.

Editar 2 Outro truque do nderscore, 2 funções mescladas em 1. Em seguida, dois parênteses removeram a fusão de expressões separadas por vírgula em uma. Legibilidade próxima a 0. Nota: Não arredondar poderia salvar outros 2 caracteres (| 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

Teste no console do 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)))

Resultado:

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

Ungolfed

NB A função D tenta criar uma Data com determinado ano, mês, dia, mas retorna false se a data criada não for a que foi pretendida (! = Dia ou mês)

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  
)   
edc65
fonte
@nderscore OK para alterações em D, erro de sintaxe para o outro. Mas salvo ainda mais de qualquer maneira
edc65
Esquisito. Algo deve ter acontecido quando colei no comentário. Suas últimas otimizações torná-lo irrelevante embora :)
nderscore
1
Colocar isso em uma pasta, como eu não confiar em comentários de SE mais: (-3) pastie.org/private/6bemdweyndcaiseay70kia
nderscore
4

C # no LINQPad - 446 408 272 Bytes

Terceiro Edit: Obrigado Le Canard fou por apontar que DateTime.Today está correto, não DateTime.Now. Segundo Edit: Obrigado VisualMelon por esta solução inteligente!

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

Edit: Obrigado a podiluska e edc65 por me ajudarem a reduzir o código! Também notei que minha solução não estava correta se a entrada do ano tivesse 4 bytes, portanto, incluí a correção para esse problema. A pontuação para esta solução é 408 bytes.

Embora não esteja superando nenhuma das respostas anteriores, ainda queria compartilhar minha solução C #. Qualquer ajuda / sugestão é apreciada! ;)

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

Versão formatada e não destruída:

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

Tentei criar uma solução em que a parte "DateTime.TryParse" não se repete como nesta solução, mas tinha 21 bytes a mais.

Solução sem repetir "DateTime.TryParse": 467 bytes

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

Versão não destruída:

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;
    }
tsavinho
fonte
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];
7898 #
2
sugestão: usar ternária (:), quando possível, em vez de if / else?
edc65
1
@ThomasW. Eu não acho que desde que y tenha 2 valores diferentes, uma vez depende de a, a outra vez depende de e. Obrigado mesmo assim!
tsavinho
1
Remover as DateTime.TryParsechamadas foi meu primeiro instinto e substituí-lo por um lambda que também colocava o valor novamente em q. Também realizou algumas outras etapas ( pastebin ) para obter 328chars: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 Uau, você é realmente bom em golfe de código! Eu nunca vi isso Action<string>antes, para poder aprender algo com você;) Consegui reduzir sua resposta para 318 caracteres substituindo q.Where(i=>i>=DateTime.Now).Countpor q.Count(i=>i>=DateTime.Now. Também removi os suportes xpara poder salvar mais 2 caracteres!
tsavinho
3

Haskell, 171 165 caracteres

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)

O nome da função é %. Execute com a data do teste como uma tupla em ordem canônica (y, m, d) com o ano real e o carimbo da caixa como uma tupla de três números:

λ: (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
MtnViewMark
fonte
2

Erlang, 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).

A função de teste seria:

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

Esta solução depende da compreensão da lista. Ele empresta o truque do módulo para o ano da solução Haskell. Ele também é usado calendar:valid_date/1para lidar com datas impossíveis devido ao número de dias em um determinado mês (por exemplo, "29-2-2" pode estar apenas no formato YMD). Além disso, Hoje está no date()formato de Erlang (uma tupla YMD).

Paul Guyot
fonte
2

APL (85)

Isso usa algumas das novas funções do Dyalog APL 14, mas nenhuma biblioteca externa. Para variar, funciona no TryAPL .

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

Essa é uma função que usa a matriz de 3 elementos como argumento do lado direito ( ) e a data a ser comparada como argumento do lado esquerdo ( ), como um número inteiro de YYYYMMDDformato. Ou seja, a data 2014-07-09é representada como o número 20140709.

Teste:

      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

Explicação:

  • Z←(⊂⌽⍵),(⊂2⌽⍵),⊂⍵: transforme a data especificada no formato YMD, invertendo (⊂⌽⍵), girando-a para a esquerda por 2 (⊂2⌽⍵)ou simplesmente não fazendo nada ⊂⍵. Agora, pelo menos um deles é uma data adequada no formato YMD, talvez mais de um se a data for ambígua.
  • {∧/12 31≥1↓⍵}¨Z: teste se cada data é válida: o ano (primeiro elemento) é descartado e, em seguida, o mês não deve ser maior que 12 e o dia não deve ser maior que 31.
  • Z/⍨: filtre as datas válidas de Z.
  • {... : para cada data válida:
    • ⍵+(99≥⊃⍵)×3↑1900+100×50>⊃⍵: se o ano não for superior a 99, adicione 1900 e 100 se o ano for inferior a 50.
    • (3/100)⊥: decodifique como se fosse um conjunto de números da base 100. (O ano é superior a 100, mas isso não importa, pois é o primeiro elemento.) Isso fornece um número para cada data válida no mesmo formato que o argumento esquerdo.
  • ⍺≤: para cada data, veja se não é menor que . Isso fornecerá um vetor binário em que 1 significa OKe 0 significa spoiled.
  • 100×(+/÷⍴): divida a soma do vetor binário pelo seu comprimento e multiplique por 100.
marinus
fonte
Salve 7 bytes (e bata K em uma boa margem) com encalhar e tornar uma função interna tácita:{100×(+/÷⍴)⍺≤((3/100)⊥⊢+(99≥⊃)×3↑1900+100×50>⊃)¨Z/⍨{∧/12 31≥1↓⍵}¨Z←(⌽⍵)(2⌽⍵)⍵}
Adám 29/17/17
0

Java: 349 caracteres (3 sem espaços)

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

Aqui está uma classe que pode ser usada para testá-lo, incluindo uma versão (ligeiramente) degolfada do método:

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+"%");
   }   
}

Esta é minha primeira partida de golfe com código e acho que descobri por que não costumo ver muitos jogadores de Java.

shieldgenerator7
fonte
1
Você precisa aceitar um int[]argumento como, não três ints.
Joey
ok, eu consertei.
precisa saber é o seguinte
0

Bytes em 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);}}}

Golfe pela primeira vez, procurando conselhos. Notavelmente, removendo bytes devido ao espaço para nome.

Abusar do fato de que apenas uma função é necessária, e não um programa real. Além disso, a função sempre resulta em uma exceção não capturada.

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); 
        } 
    } 
}
Le Canard fou
fonte
0

Mathematica , 118

Usando o código do m.buettner como ponto de partida, tenho algumas melhorias:

⌊100Mean@UnitStep@Cases[DateDifference@{If[#<100,Mod[#+50,100]+1950,#],##2}&@@@{#,RotateRight@#,Reverse@#},_Integer]⌋&
Mr.Wizard
fonte
O golfe pode ser uma função que usa uma lista de três int como argumento.
algorithmshark
@algorithmshark Thanks. Não sei como senti falta disso. Atualizando ...
Mr.Wizard