Il mio latte è scaduto?


98

Oh, amico, questa data di scadenza non scrive i mesi con le lettere! Non so se scade il 10 marzo o il 3 ottobre ... Aspetta, no, non importa, l'anno dice il 2012. (vicolo-oops ha usato mezzo mattone di formaggio nella spazzatura come un professionista)

Quindi supponiamo per un momento che sei troppo occupato per cercare di capire quando questo barattolo di marinara dovrebbe scadere. Vuoi solo la versione di Cliff Notes: quanto è probabile che sia scaduto? Scriviamo un po 'di codice!

Sai che i produttori stampano la data come un triplo ordinato di numeri interi, in uno dei tre formati:

YEAR  MONTH DAY
MONTH DAY   YEAR
DAY   MONTH YEAR

E sai che alcune date possono essere interpretate solo in uno o due modi, non tutte e tre: il 55 in 55-11-5deve essere un anno, il che significa che questa particolare scatola di Twinkies è scaduta il 5 novembre 1955. L'anno viene talvolta indicato in quattro cifre e non due, che possono escludere alcune opzioni. Quando sono due cifre, 50..99 significa 1950..1999 e 0..49 significa 2000..2049.

Il tuo compito è quello di scrivere un programma o una funzione che accetta un array di numeri interi che è una data valida in almeno una delle interpretazioni sopra e produce una probabilità percentuale che sia ancora buona. La probabilità percentuale è semplicemente la percentuale di interpretazioni valide della data in data successiva alla data odierna.

L'array di numeri interi sarà il [Int]tipo di lunghezza tre della tua lingua se è un argomento per una funzione e dato come numeri interi con trattino, barra o spazio (puoi scegliere) se usato come input su STDIN in un programma completo. *

La "data odierna" può essere la data effettiva di oggi, ottenuta tramite una funzione di data o la data indicata in un argomento aggiuntivo per la funzione o un parametro aggiuntivo in STDIN. Può essere in epoca Unix secondi, un'altra tripla anno-mese-giorno inserita in una delle tre modalità sopra, o un'altra modalità più conveniente.

Facciamo alcuni esempi! L'input della data di scadenza sarà nello stile separato da trattini e supponiamo per gli esempi seguenti che la data odierna sia il 5 luglio 2006.

  • 14-12-14- Entrambe le interpretazioni valide per questo (DMY e YMD) sono equivalenti, 14 dicembre 2014. L'output è 100 perché questo prodotto è sicuramente ancora buono.
  • 8-2-2006- L'ultimo numero è sicuramente un anno, dato che ha quattro cifre. Potrebbe essere l'8 febbraio (scaduto) o il 2 agosto (ancora valido). L'output è 50 .
  • 6-7-5- Potrebbe essere qualsiasi cosa! L'interpretazione del "5 luglio 2006" è ancora valida (solo per un giorno), ma le restanti due sono entrambe nel 2005 e dovrebbero essere lanciate il più rapidamente possibile. L'output è 33 .
  • 6-5-7- Qui, due interpretazioni su tre sono al sicuro. Puoi arrotondare il tuo decimale su o giù, quindi 66 o 67 vanno bene.
  • 12-31-99- Va bene, questo è inequivocabilmente dall'inizio del secolo (gli anni da 50 a 99 sono 19XX e 31 non possono essere un mese). Un grande grasso 0 , e dovresti davvero pulire il tuo frigorifero più spesso.

Puoi tranquillamente supporre che qualsiasi input che non soddisfa gli standard di cui sopra non sia a conoscenza delle regole di output sopra.

Nessuna richiesta web o scappatoie standard. Le librerie di gestione della data sono consentite. Questo è il golf del codice: vinca il programma più breve.

* Se si utilizza brainfuck o un linguaggio per handicappati di tipo di dati simile, è possibile assumere che i valori ASCII dei primi tre caratteri in input siano i numeri interi per la data. Questo esclude la logica dell'anno a quattro cifre, certo, ma penso che saremmo troppo stupiti nel vedere una soluzione a Brainfuck per offenderti.


39
Umm ... l'anno in corso è il 2014, non il 2006. Il tuo latte ha superato gli otto anni al massimo.
John Dvorak,

11
@JanDvorak Non volevo sforzarmi molto per costruire esempi significativi, quindi ho modificato la data di oggi per semplificare.
algoritmo

7
@ Dgrin91 non mi interessa, li mangerò ancora: D
aditsu,

6
In Australia, il latte scade circa una settimana prima dell'uso per data
gnibbler

5
Dovresti aggiungere un test con un 00, poiché non può essere un giorno o un mese legale.
MtnViewMark

Risposte:


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}

Richiamare con xof .z.D(un builtin) per il confronto con oggi o una data letterale a scelta altrimenti:

  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

Questo è fondamentalmente un porto della soluzione Python di @ Alex-l's, con alcuni trucchi di golf vari aggiunti:

  • Le istruzioni di riorganizzazione sono codificate in una stringa per salvare un paio di caratteri.
  • La logica condizionale (ab) usa la verità come numero intero (ma in modo diverso dalla soluzione Python).
  • Il test di validità è leggermente diverso: k4 / q analizzerà felicemente qualsiasi stringa in qualsiasi tipo di dati; restituisce semplicemente un valore nullo se non ha senso. Pertanto, restituisco un elenco di date dalla funzione interna, che può essere o non essere nulla.
  • Il risultato finale viene dal controllo di quante possibili interpretazioni della data sono nulle rispetto a quante sono inferiori alla data di confronto; è importante qui che la data nulla sia considerata inferiore a qualsiasi altra data.

1
Puoi salvare un carattere rimuovendo l'ultimo 0 da "012201210", poiché #prende i suoi elementi ciclicamente. In realtà, è possibile salvare una seconda char questo modo scambiando gli ultimi due casi: 3 3#.:'"0122102".
algoritmo

Hai rasato un altro carattere invertendo gli argomenti della funzione interna, salvando le parentesi (ma aggiungendo un contrario). Qualcuno può aiutarmi a salvare altri due caratteri? APL mi sta battendo!
Aaron Davies,

Ne ho rasati altri cinque riscrivendo la matematica alla fine. Di nuovo in testa!
Aaron Davies,

E se mi chino a scrivere seriamente il codice non funzionale, posso radere un altro byte inquinando il namespace globale: {c*(+/~d<x)%3-+/^d:{"D"$"."/:$|z,y,x+(c*19+x<50)*x<c::100}.'y@/:3 3#.:'$21020101}.
Aaron Davies,

14

Rubino, 115 caratteri

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}

Ciò definisce una funzione fche accetta due argomenti: un array che contiene l'input e la data "odierna".

Esempi:

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

Uso il modulo datetime per la validità e il confronto delle date. Se datenon è possibile ottenere un datetime valido dall'input, viene generato ValueError. In questo modo sè la somma delle date non scadute ed tè il numero totale di date valide. Sto sfruttando il fatto che True == 1ai fini dell'aggiunta e dell'indicizzazione in Python. Salvo anche un personaggio usando 25 * (76,80) anziché (1900,2000).

Nota che le righe nel secondo livello di rientro usano un carattere tab, non 2 spazi.

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

Aggiungi questo alla fine per testare:

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)
  • Immettere come int[]tramite parametro, ad es

    PS> ./milk.ps1 5,6,7
    
  • I messaggi di errore vengono silenziati tramite try/ catch, purché non so se l'output su stderr è consentito o meno.
  • Usando +"-1"la data, che viene interpretata come .AddDays(-1)spostare la data corrente di un giorno, in modo che possiamo confrontare con ieri (anziché solo oggi). Questo risolve il problema che otteniamo una data con 0:00 come ora ma dobbiamo confrontare con una data con ora da oggi.
  • Ormai fortemente foderato
  • Utilizzare un nuovo trucco per ridurre al minimo gli errori , un po 'più breve

6

R, 269

Mi aspettavo che fosse facile in R, ma gli anni a una cifra erano una palla curva piuttosto grande. Penso che questo potrebbe essere molto meglio di quello che è.

lubridateè un pacchetto di CRAN, potrebbe essere necessario installarlo 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))dove c(d1,d2,d3)è un vettore di numeri interi.

es . f(c(6,10,14))ritorni 0.3333333.

Il lubridatepacchetto ha una serie di funzioni wrapper per l'analisi delle date in diversi ordini. Li uso per vedere quali formati producono date valide, butto quelle non valide e poi quali non si sono ancora verificati.


6

Mathematica, 163 153 164 byte

( modifica: date fisse al di fuori dell'intervallo 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]]&

Questo definisce una funzione che puoi chiamare come

f[{6,7,5}]

Attualmente, la percentuale non è arrotondata (in attesa che il PO chiarisca).

Ecco una spiegazione un po 'lungo che dovrebbe essere comprensibile senza alcuna conoscenza Mathematica (nota che &rende tutto resta di esso una funzione anonima i cui parametri sono indicati come #, #2, #3...):

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

Questo definisce una funzione, che trasforma 3 parametri a,b,cin 3 liste {{a,b,c},{c,b,a},{c,a,b}. Nota che ##è solo una sequenza di tutti i parametri.

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

Applicato alla data di scadenza, fornisce un elenco di {y,m,d}ciascuna delle tre possibili permutazioni.

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

Questa è una funzione anonima che accetta tre parametri a,b,ce restituisce un elenco dei tre, in cui il primo è stato convertito in un anno secondo le regole indicate: i numeri tra 50e 99(modulo 100) vengono trasformati in un anno del 20 ° secolo, i numeri tra 0e 49( modulo 100) vengono trasformati in un anno del 21 ° secolo, tutti gli altri vengono lasciati avanti. Qui, ##2c'è una sequenza di parametri che inizia con il secondo, cioè b,c.

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

Applicato a ciascuno dei tre risultati precedenti, questo canonicalizza solo i formati dell'anno. Chiamiamolo canonicalDatesper abbreviare la seguente espressione:

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

Questo filtra le interpretazioni non valide. DateList@drende una {y,m,d,h,m,s}rappresentazione completa di vari formati di data. Interpreterà le liste nello stesso ordine, ma il trucco è che puoi passarle cose come {8,2,2006}nel qual caso calcolerà 8 years + 2 months + 2006 days. Quindi controlliamo che i primi tre elementi dell'elenco restituito siano identici all'input (che può accadere solo se il mese e il giorno negli intervalli appropriati).

Per abbreviare le seguenti righe, farò riferimento al risultato di quell'espressione validDatesda ora in poi:

DateDifference[#,Date[]]&

Un'altra funzione anonima che prende una data e restituisce la differenza in giorni ad oggi (ottenuta da Date[]).

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

Mappalo sulle interpretazioni della data valide.

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

Ancora un'altra funzione anonima che, data una lista ( #), restituisce la percentuale di numeri non positivi in ​​quella lista. Non .è una moltiplicazione ma solo la cifra decimale, per evitare numeri razionali come risultato (otterresti cose come 100/3invece di 33.333- non so davvero se questo è un problema).

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

Applicato all'elenco delle differenze di data, questo ci dà la frazione di interpretazioni che non sono ancora scadute.


Penso che tu abbia erroneamente convertito anni come 2999 o 2099 in 1999.
Ventero,

@Ventero è vero. Pensavo che avessimo a che fare solo con gli anni 1950-2049 (e le loro versioni a 1 o 2 cifre), ma rileggendo la sfida non si fa menzione di ciò.
Martin Ender,

@Ventero risolto (ma mi avevi già battuto in modo significativo comunque);)
Martin Ender

Sono sorpreso di vedere che hai un account su Mathematica ma non hai pubblicato domande o risposte. Qualcosa ti sta trattenendo?
Mr.Wizard,

@ Mr.Wizard scusa, ho completamente dimenticato di risponderti. Domande: finora ogni problema che ho avuto potrebbe essere risolto con googling / altre domande SE. Risposte: Non so ... Credo che io non considero me stesso come quella abile quando si tratta di utilizzare Mathematica produttivamente ... Lo uso solo per frammenti veloci qui e là (e il codice di golf). Inoltre, suppongo di rispondere alle domande che dovrei guardare attivamente a nuovi per vedere cosa posso rispondere, e attualmente tutto il mio tempo SE è assegnato per PPCG. ;) Se vuoi che mi convinca altrimenti, sentiti libero di farlo in chat! :)
Martin Ender,

4

JavaScript (E6) 159 164 172

Modifica Grazie a nderscore per i suggerimenti e per avermi spinto a ripensarci. Riorganizzato D evitando parametri e tagliando alcuni caratteri.

Modifica 2 Un altro trucco di nderscore, 2 funzioni unite in 1. Quindi due parentesi rimosse unendo espressioni separate da virgola in una. Precisione di lettura vicino a 0. Sidenote: il non arrotondamento potrebbe salvare altri 2 caratteri (| 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 nella console 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)))

Produzione:

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

Ungolfed

NB La funzione D tenta di creare una data con un determinato anno, mese, giorno ma restituisce false se la data di creazione non è quella desiderata (! = Giorno o mese)

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 OK per le modifiche in D, errore di sintassi per l'altro. Ma risparmiamo ancora di più
edc65

Strano. Deve essere successo qualcosa quando l'ho incollato nel commento. Le tue ultime ottimizzazioni lo rendono comunque irrilevante :)
nderscore

1
Mettendo questo in un incolla, poiché non mi fido più dei commenti di SE: (-3) pastie.org/private/6bemdweyndcaiseay70kia
nderscore

4

C # in LINQPad - 446 408 272 byte

Terza modifica: grazie a Le Canard fou per aver sottolineato che DateTime. Oggi è corretto, non DateTime.Now. Seconda modifica: grazie a VisualMelon per questa soluzione intelligente!

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

Modifica: grazie a podiluska ed edc65 per avermi aiutato a mettere in corto il codice! Ho anche notato che la mia soluzione non era corretta se l'input dell'anno era lungo 4 byte, quindi ho incluso la correzione per quel problema. Il punteggio per questa soluzione è 408 byte.

Anche se non sto battendo nessuna delle risposte precedenti, volevo comunque condividere la mia soluzione C #. Qualsiasi aiuto / suggerimento è apprezzato! ;)

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

Versione formattata e non modificata:

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

Ho cercato di creare una soluzione in cui la parte "DateTime. TryParse" non viene ripetuta come in questa soluzione, ma era più lunga di 21 byte.

Soluzione senza ripetere "DateTime. TryParse": 467 byte

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

Versione non golfata:

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];
podiluska

2
suggerimento: usa ternary (? :) quando possibile invece di if / else
edc65

1
@ThomasW. Non penso che poiché y abbia 2 valori diversi, una volta dipende da a, l'altra volta dipende da e. Grazie comunque!
Tsavinho,

1
Rimuovere le DateTime.TryParsechiamate è stato il mio primo istinto, sostituito con un lambda che ha anche riportato il valore in q. Ha anche eseguito alcuni altri passaggi ( pastebin ) per ottenere 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 Wow, sei davvero bravo a giocare a golf! Non ho mai visto Action<string>prima, quindi ho potuto imparare qualcosa da te;) Sono stato in grado di ottenere la tua risposta fino a 318 caratteri sostituendoli q.Where(i=>i>=DateTime.Now).Countcon q.Count(i=>i>=DateTime.Now. Ho anche rimosso le parentesi in xmodo da poter salvare altri 2 personaggi!
Tsavinho,

3

Haskell, 171 165 caratteri

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)

Il nome della funzione è %. Esegui con la data del test come tupla nell'ordine canonico (y, m, d) con l'anno effettivo e il timbro del cartone come una tupla di tre numeri:

λ: (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

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 funzione di test sarebbe:

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

Questa soluzione si basa sulla comprensione dell'elenco. Prende in prestito il trucco del modulo per l'anno dalla soluzione Haskell. Utilizza anche calendar:valid_date/1per gestire date impossibili a causa del numero di giorni in un determinato mese (ad es. "29-2-2" può essere solo in formato YMD). Inoltre, Today è nel date()formato di Erlang (una tupla YMD).


2

APL (85)

Questo utilizza alcune delle nuove funzioni di Dyalog APL 14, ma nessuna libreria esterna. Per una modifica, funziona su TryAPL .

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

Questa è una funzione che accetta l'array a 3 elementi come argomento sul lato destro ( ) e la data da verificare come argomento sul lato sinistro ( ), come numero intero di YYYYMMDDformato. Cioè, la data 2014-07-09è rappresentata come il numero 20140709.

Test:

      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

Spiegazione:

  • Z←(⊂⌽⍵),(⊂2⌽⍵),⊂⍵: trasforma la data in formato YMD capovolgendola (⊂⌽⍵), ruotandola a sinistra di 2 (⊂2⌽⍵)o semplicemente non facendo nulla ⊂⍵. Almeno uno di questi è ora una data corretta in formato YMD, forse più di una se la data è ambigua.
  • {∧/12 31≥1↓⍵}¨Z: verifica se ogni data è valida: l'anno (primo elemento) viene eliminato, quindi il mese non deve essere superiore a 12 e il giorno non deve essere superiore a 31.
  • Z/⍨: filtra le date valide da Z.
  • {... : per ogni data valida:
    • ⍵+(99≥⊃⍵)×3↑1900+100×50>⊃⍵: se l'anno non è superiore a 99, aggiungere 1900, quindi 100 se l'anno è inferiore a 50.
    • (3/100)⊥: decodificalo come se fosse un insieme di numeri base-100. (L'anno è superiore a 100, ma questo non ha importanza in quanto è il primo elemento.) Ciò fornisce un numero per ogni data valida nello stesso formato dell'argomento sinistro.
  • ⍺≤: per ogni data, vedere se non è inferiore a . Questo darà un vettore binario dove 1 significa OKe 0 significa spoiled.
  • 100×(+/÷⍴): dividere la somma del vettore binario per la sua lunghezza e moltiplicare per 100.

Risparmia 7 byte (e batti K con un bel margine) con lo sforzo e rendendo tacita una funzione interna:{100×(+/÷⍴)⍺≤((3/100)⊥⊢+(99≥⊃)×3↑1900+100×50>⊃)¨Z/⍨{∧/12 31≥1↓⍵}¨Z←(⌽⍵)(2⌽⍵)⍵}
Adám

0

Java: 349 caratteri (3 senza spazi)

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

Ecco una classe contenente che può essere utilizzata per testarla, inclusa una versione (leggermente) degolfata del metodo:

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

Questo è il mio primo round di code golf e penso di aver capito perché di solito non vedo molti golfisti Java.


1
Devi accettare un int[]argomento come, non tre ints.
Joey,

ok, l'ho risolto.
shieldgenerator7,

0

C # 287 byte

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

Giocare a golf per la prima volta, in cerca di consigli. In particolare, rimuovere i byte a causa dello spazio dei nomi.

Abusare del fatto che è necessaria solo una funzione, non un programma reale. Inoltre, la funzione comporta sempre un'eccezione non rilevata.

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

Mathematica , 118

Usando il codice di m.buettner come punto di partenza ho alcuni miglioramenti:

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

Il golf può essere una funzione che prende un elenco di tre Int come argomento.
algoritmo

@algorithmshark Grazie. Non so come mi sia perso. Aggiornamento ...
Mr.Wizard
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.