¿Mi leche ha expirado?

98

¡Vaya, hombre, esta fecha de vencimiento no escribe los meses con letras! No puedo decir si caducará el 10 de marzo o el 3 de octubre ... Espera, no, no importa, el año dice 2012. (callejón oops ladrillo de queso medio usado en el basurero como un profesional)

Entonces, supongamos por un momento que estás demasiado ocupado para tratar de razonar cuando se supone que este frasco de marinara caducará. Solo quiere la versión de Cliff Notes: ¿qué tan probable es que esté vencida? ¡Escribamos un código!

Usted sabe que los fabricantes imprimen la fecha como un triple ordenado de enteros, en uno de tres formatos:

YEAR  MONTH DAY
MONTH DAY   YEAR
DAY   MONTH YEAR

Y usted sabe que algunas fechas solo pueden interpretarse de una o dos maneras, no las tres: la 55 en 55-11-5tiene que ser un año, lo que significa que esta caja particular de Twinkies expiró el 5 de noviembre de 1955. El año a veces se da en cuatro dígitos y no dos, lo que puede descartar algunas opciones. Sin embargo, cuando son dos dígitos, 50..99 significa 1950..1999 y 0..49 significa 2000..2049.

Su trabajo es escribir un programa o función que tome una matriz de enteros que sea una fecha válida en al menos una de las interpretaciones anteriores, y genere un porcentaje de probabilidad de que todavía sea buena. El porcentaje de probabilidad es simplemente el porcentaje de interpretaciones válidas de la fecha que son posteriores o posteriores a la fecha de hoy.

La matriz de enteros será el [Int]tipo de longitud de su idioma tres si es un argumento para una función, y se dará como enteros con guiones, barras o espacios separados (puede elegir) si se usa como entrada en STDIN para un programa completo. *

La "fecha de hoy" puede ser la fecha real de hoy, tal como se obtiene a través de una función de fecha, o la fecha dada en un argumento adicional para la función o parámetro adicional en STDIN. Puede ser en segundos de época de Unix, otro triple año-mes-día ingresado en una de las tres formas anteriores, u otra forma más conveniente.

¡Tengamos algunos ejemplos! La entrada de la fecha de vencimiento estará en un estilo separado por guiones, y suponga para los ejemplos a continuación que la fecha de hoy es el 5 de julio de 2006.

  • 14-12-14- Ambas interpretaciones válidas para esto (DMY e YMD) son equivalentes, 14 de diciembre de 2014. El resultado es 100 porque este producto definitivamente sigue siendo bueno.
  • 8-2-2006- El último número es un año, seguro, ya que tiene cuatro dígitos. Esto podría ser el 8 de febrero (caducado) o el 2 de agosto (aún bueno). La salida es 50 .
  • 6-7-5- ¡Esto podría ser cualquier cosa! La interpretación del "5 de julio de 2006" sigue siendo buena (solo por un día), pero las dos restantes corresponden a 2005 y deben descartarse lo más rápido posible. La salida es 33 .
  • 6-5-7- Aquí, dos de cada tres interpretaciones son seguras. Puede redondear su decimal hacia arriba o hacia abajo, por lo que 66 o 67 están bien.
  • 12-31-99- Bien, este es inequívocamente desde el cambio de siglo (los años del 50 al 99 son 19XX, y el 31 no puede ser un mes). Un gran 0 gordo , y realmente deberías limpiar tu refrigerador con más frecuencia.

Puede asumir con seguridad que cualquier entrada que no cumpla con los estándares anteriores no está al tanto de las reglas de salida anteriores.

No hay solicitudes web ni lagunas estándar. Se permiten bibliotecas de manejo de fechas. Este es el código de golf: que gane el programa más corto.

* Si está utilizando brainfuck o algún lenguaje con discapacidad similar al tipo de datos, puede suponer que los valores ASCII de los primeros tres caracteres de entrada son los enteros de la fecha. Esto excluye la lógica del año de cuatro dígitos, claro, pero creo que estaríamos demasiado asombrados al ver una solución a esto en Brainfuck para desacreditarlo.

Algoritmo de tiburón
fuente
39
Umm ... el año actual es 2014, no 2006. Su leche ha caducado en el mejor de los últimos ocho años.
John Dvorak
11
@ JanDvorak Simplemente no quería esforzarme mucho para construir ejemplos significativos, así que modifiqué la fecha de hoy para que sea más fácil.
algorithmshark
77
@ Dgrin91 no me importa, todavía los comeré: D
aditsu
66
En Australia, la leche caduca aproximadamente una semana antes del uso por fecha
gnibbler
55
Debe agregar una prueba con un 00, ya que no puede ser un día o mes legal.
MtnViewMark

Respuestas:

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 con xof .z.D(un incorporado) para compararlo con el día de hoy, o con una fecha literal de su elección de lo contrario:

  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

Esto es básicamente un puerto de la solución Python de @ Alex-l, con algunos trucos de golf agregados:

  • Las instrucciones de reordenamiento están codificadas en una cadena para guardar un par de caracteres.
  • La lógica condicional (ab) usa la verdad como número entero (pero de manera diferente a la solución de Python).
  • La prueba de validez es ligeramente diferente: k4 / q con gusto analizará cualquier cadena en cualquier tipo de datos; simplemente devuelve un valor nulo si no tiene sentido. Por lo tanto, devuelvo una lista de fechas de la función interna, que puede ser nula o no.
  • El resultado final proviene de verificar cuántas de las posibles interpretaciones de fechas son nulas frente a cuántas son menores que la fecha de comparación; Aquí es importante que la fecha nula se considere menor que cualquier otra fecha.
Aaron Davies
fuente
1
Puede guardar un carácter eliminando el último 0 de "012201210", ya que #toma sus elementos de forma cíclica. De hecho, puede guardar una segunda carbón de esta manera mediante el canje de los dos últimos casos: 3 3#.:'"0122102".
algorithmshark
Afeitó un personaje más invirtiendo args de funciones internas, salvando a los parens (pero agregando un reverso). ¿Alguien puede ayudarme a salvar otros dos caracteres? ¡APL me está ganando!
Aaron Davies
Afeitó otros cinco reescribiendo las matemáticas al final. De vuelta a la cabeza!
Aaron Davies
Y si me rebajaría a escribir código en serio no funcional, puedo afeitar otro byte contaminando el espacio de nombres 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}

Esto define una función fque toma dos argumentos: una matriz que contiene la entrada y la fecha "de hoy".

Ejemplos:

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
fuente
12

Python 2.7 - 172

Yo uso el módulo de fecha y hora para la validez y la comparación de fechas. Si dateno puede hacer una fecha y hora válida de la entrada, se eleva ValueError. De esta manera ses la suma de las fechas no vencidas y tes el número total de fechas válidas. Estoy aprovechando el hecho de queTrue == 1 para propósitos de adición e indexación en Python. También guardo un personaje usando 25 * (76,80) en lugar de (1900,2000).

Tenga en cuenta que las líneas en el segundo nivel de sangría usan un carácter de tabulación, no 2 espacios.

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

Agregue esto al final para probar:

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
fuente
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 a int[]través de parámetros, p. Ej.

    PS> ./milk.ps1 5,6,7
    
  • Los mensajes de error se silencian a través de try/catch , siempre que no sepa si la salida en stderr está permitida o no.
  • Usando +"-1"en la fecha, que se interpreta como.AddDays(-1) un cambio de la fecha actual en un día, para que podamos comparar con ayer (en lugar de solo hoy). Esto resuelve el problema de que obtenemos una fecha con 0:00 como hora, pero necesitamos compararla con una fecha con la hora de hoy.
  • Muy en línea por ahora
  • Usar un nuevo truco para silenciar errores que es bastante más corto
Joey
fuente
6

R, 269

Esperaba que esto fuera fácil en R, pero los años de un solo dígito fueron una bola curva bastante grande. Siento que esto podría ser mucho mejor de lo que es.

lubridatees un paquete de CRAN, es posible que deba instalarlo con 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))donde c(d1,d2,d3)es un vector de enteros.

Por ejemplo, f(c(6,10,14))devoluciones 0.3333333.

El lubridatepaquete tiene una serie de funciones de contenedor para analizar fechas en diferentes órdenes. Los uso para ver qué formatos producen fechas válidas, descartar las inválidas y luego ver cuáles aún no se han producido.

Shadowtalker
fuente
6

Mathematica, 163 153 164 bytes

( editar: fechas fijas fuera del rango 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]]&

Esto define una función que puede llamar como

f[{6,7,5}]

Actualmente, el porcentaje no está redondeado (esperando que el OP se aclare).

Aquí es un poco larga explicación que debe ser comprensible sin ningún conocimiento Mathematica (nota que &hace que todo lo que queda de ella una función anónima, cuyos parámetros se conocen como #, #2, #3...):

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

Esto define una función, que convierte 3 parámetros a,b,cen 3 listas {{a,b,c},{c,b,a},{c,a,b}. Tenga en cuenta que ##es solo una secuencia de todos los parámetros.

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

Aplicado a la fecha de caducidad, esto proporciona una lista de {y,m,d}cada una de las tres posibles permutaciones.

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

Esta es una función anónima que toma tres parámetros a,b,cy devuelve una lista de los tres, donde el primero se ha convertido a un año según las reglas dadas: los números entre 50y 99(módulo 100) se convierten en un año del siglo XX, los números entre 0y 49( módulo 100) se convierten en un año del siglo XXI, todos los demás quedan. Aquí, ##2hay una secuencia de parámetros que comienza con el segundo, es decir b,c.

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

Aplicado a cada uno de los tres resultados anteriores, esto solo canoniza los formatos del año. Llamemos a esto canonicalDatespara acortar la siguiente expresión:

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

Esto filtra las interpretaciones no válidas. DateList@drealiza una {y,m,d,h,m,s}representación completa de varios formatos de fecha. Interpretará las listas en el mismo orden, pero el problema es que puede pasar cosas como {8,2,2006}en cuyo caso se calculará 8 years + 2 months + 2006 days. Por lo tanto, verificamos que los primeros tres elementos de la lista devuelta sean idénticos a la entrada (que solo puede suceder si el mes y el día están en los rangos apropiados).

Para acortar las siguientes líneas, me referiré al resultado de esa expresión a partir validDatesde ahora:

DateDifference[#,Date[]]&

Otra función anónima que toma una fecha y devuelve la diferencia en días hasta hoy (obtenida de Date[]).

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

Asigne eso en las interpretaciones de fechas válidas.

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

Otra función anónima que, dada una lista ( #), devuelve el porcentaje de números no positivos en esa lista. El .no es una multiplicación, sino solo el dígito decimal, para evitar números racionales como resultado (obtendría cosas como en 100/3lugar de 33.333, en realidad no sé si eso es un problema).

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

Aplicado a la lista de diferencias de fechas, esto nos da la fracción de interpretaciones que aún no han expirado.

Martin Ender
fuente
Creo que convertiste incorrectamente años como 2999 o 2099 a 1999.
Ventero
@Ventero eso es cierto. Asumí que solo estábamos lidiando con los años 1950-2049 (y sus versiones de 1 o 2 dígitos), pero releyendo el desafío no hay mención de eso.
Martin Ender
@Ventero arreglado (pero de todas formas ya me habías golpeado significativamente))
Martin Ender
Me sorprende ver que tiene una cuenta en Mathematica pero no ha publicado ninguna pregunta o respuesta. ¿Hay algo que te detiene?
Mr.Wizard
@ Mr.Wizard lo siento, olvidé totalmente responderte. Preguntas: hasta ahora, cada problema que tenía podría resolverse con google / otras preguntas SE. Respuestas: no sé ... supongo que no lo veo como que competentes cuando se trata de usar Mathematica productiva ... sólo lo uso para los fragmentos rápidos aquí y allí (y el campo de código). Además, supongo que para responder preguntas tendría que mirar activamente otras nuevas para ver qué puedo responder, y actualmente todo mi tiempo de SE está asignado para PPCG. ;) Si quieres convencerme de lo contrario, ¡no dudes en hacerlo en el chat! :)
Martin Ender
4

JavaScript (E6) 159164172

Editar Gracias a nderscore por las sugerencias y por empujarme a pensar de nuevo. Reorganizó D evitando parámetros y cortando algunos caracteres.

Editar 2 Otro truco de nderscore, 2 funciones fusionadas en 1. Luego, dos paréntesis eliminaron las expresiones separadas por comas en una. Legibilidad cercana a 0. Nota de advertencia: no redondear podría ahorrar otros 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

Prueba en la consola 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)))

Salida:

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

Sin golf

Nota: la función D intenta crear una fecha con un año, mes y día determinados, pero devuelve falso si la fecha creada no es la que se pretendía (! = Día o mes)

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
fuente
@nderscore OK para cambios en D, error de sintaxis para el otro. Pero ahorró aún más de todos modos
edc65
Extraño. Algo debe haber sucedido cuando lo pegué en el comentario. Sin embargo, sus últimas optimizaciones lo hacen irrelevante :)
nderscore
1
Poniendo esto en una pasta, ya que ya no confío en los comentarios de SE: (-3) pastie.org/private/6bemdweyndcaiseay70kia
nderscore
4

C # en LINQPad - 446 408 272 Bytes

Tercera edición: Gracias a Le Canard fou por señalar que DateTime.Today es correcto, no DateTime.Now. Segunda edición: ¡ Gracias VisualMelon por esta solución 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();}

Editar: ¡ Gracias a podiluska y edc65 por ayudarme a acortar el código! También noté que mi solución no era correcta si la entrada del año era de 4 bytes, por lo tanto, incluí la solución para ese problema. El puntaje para esta solución es 408 Bytes.

Aunque no estoy superando ninguna de las respuestas anteriores, todavía quería compartir mi solución C #. Cualquier ayuda / sugerencia es 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();}

Versión formateada y sin golf:

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

Traté de hacer una solución donde la parte "DateTime. TryParse" no se repite como en esta solución, pero fue 21 bytes más.

Solución sin 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;}

Versión sin golf:

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
fuente
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];
podiluska
2
sugerencia: use ternary (? :) cuando sea posible en lugar de if / else
edc65
1
@ThomasW. No creo que dado que y tenga 2 valores diferentes, una vez depende de a, la otra depende de e. ¡Gracias de cualquier manera!
tsavinho
1
Eliminar las DateTime.TryParsellamadas fue mi primer instinto, lo reemplacé con una lambda que también devolvió el valor a q. También realicé algunos otros pasos ( pastebin ) para obtener 328 caracteres: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, ¡eres realmente bueno en golf de códigos! Nunca lo vi Action<string>antes, así que pude aprender algo de ti;) pude obtener tu respuesta a 318 caracteres reemplazándola q.Where(i=>i>=DateTime.Now).Countpor q.Count(i=>i>=DateTime.Now. ¡También eliminé los corchetes xpara poder guardar 2 personajes más!
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)

El nombre de la función es %. Ejecute con la fecha de prueba como una tupla en orden canónico (a, m, d) con el año real, y el sello del cartón como una tupla de tres 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
fuente
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).

La función de prueba sería:

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

Sin golf

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 solución se basa en la comprensión de la lista. Toma prestado el truco del módulo para el año de la solución Haskell. También se utiliza calendar:valid_date/1para manejar fechas imposibles debido a la cantidad de días en un mes determinado (por ejemplo, "29-2-2" solo puede estar en formato YMD). Además, Today está en date()formato Erlang (una tupla YMD).

Paul Guyot
fuente
2

APL (85)

Esto utiliza algunas de las nuevas funciones de Dyalog APL 14, pero no bibliotecas externas. Para variar, funciona en TryAPL .

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

Esta es una función que toma la matriz de 3 elementos como argumento del lado derecho ( ), y la fecha para verificar como argumento del lado izquierdo ( ), como un entero de YYYYMMDDformato. Es decir, la fecha 2014-07-09se representa como el número 20140709.

Prueba:

      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

Explicación:

  • Z←(⊂⌽⍵),(⊂2⌽⍵),⊂⍵: convierte la fecha dada en formato YMD volteándola (⊂⌽⍵), girándola a la izquierda 2 (⊂2⌽⍵)o simplemente sin hacer nada ⊂⍵. Al menos uno de estos ahora es una fecha adecuada en formato YMD, tal vez más de uno si la fecha es ambigua.
  • {∧/12 31≥1↓⍵}¨Z: prueba si cada fecha es válida: el año (primer elemento) se descarta, y luego el mes no debe ser superior a 12 y el día no debe ser superior a 31.
  • Z/⍨: filtra las fechas válidas de Z.
  • {... : para cada fecha válida:
    • ⍵+(99≥⊃⍵)×3↑1900+100×50>⊃⍵: si el año no es superior a 99, agregue 1900, luego 100 si el año es inferior a 50.
    • (3/100)⊥: descifrarlo como si fuera un conjunto de números de base 100. (El año es superior a 100, pero esto no importa, ya que es el primer elemento). Esto proporciona un número para cada fecha válida en el mismo formato que el argumento izquierdo.
  • ⍺≤: para cada fecha, vea si no es menor que . Esto dará un vector binario donde 1 significa OKy 0 significa spoiled.
  • 100×(+/÷⍴): divide la suma del vector binario por su longitud y multiplica por 100.
marinus
fuente
Ahorre 7 bytes (y venza a K por un buen margen) con varamientos y haciendo una función interna tácita:{100×(+/÷⍴)⍺≤((3/100)⊥⊢+(99≥⊃)×3↑1900+100×50>⊃)¨Z/⍨{∧/12 31≥1↓⍵}¨Z←(⌽⍵)(2⌽⍵)⍵}
Adám
0

Java: 349 caracteres (3 sin espacios)

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

Aquí hay una clase que contiene que se puede usar para probarlo, incluida una versión (ligeramente) desadaptada del 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 es mi primera ronda de golf de código, y creo que descubrí por qué generalmente no veo a muchos golfistas de Java.

shieldgenerator7
fuente
1
Debe aceptar un int[]argumento, no tres ints.
Joey
Ok, lo arreglé.
shieldgenerator7
0

C # 287 bytes

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

Golf por primera vez, en busca de consejos. Notablemente, eliminando bytes debido al espacio de nombres.

Abusar del hecho de que solo se requiere una función, no un programa real. Además, la función siempre da como resultado una excepción no detectada.

Sin golf

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
fuente
0

Mathematica , 118

Usando el código de m.buettner como punto de partida, tengo algunas mejoras:

⌊100Mean@UnitStep@Cases[DateDifference@{If[#<100,Mod[#+50,100]+1950,#],##2}&@@@{#,RotateRight@#,Reverse@#},_Integer]⌋&
Señor mago
fuente
El golf puede ser una función que tome una lista de tres int como argumento.
algorithmshark
@algorithmshark Gracias. No sé cómo me perdí eso. Actualizando ...
Mr.Wizard