L'ultimo lunedì


27

Lunedì 31 ottobre è Halloween. E mi ha fatto pensare - mi chiedo che cosa gli altri mesi hanno l'ultimo giorno del mese anche essere un Lunedi?

Ingresso

  • Un numero intero positivo in qualsiasi formato conveniente che rappresenta un anno 10000 > y > 0,.
  • L'ingresso può essere riempito con zeri (ad esempio, 0025per l'anno 25), se necessario.

Produzione

  • Un elenco dei mesi di quell'anno in cui l'ultimo giorno del mese è un lunedì.
  • Può trattarsi di nomi di mesi (ad esempio, January, March, October) o nomi brevi ( Jan, Mar, Oct) o numeri ( 1, 3, 10), come righe separate o un elenco o delimitati, ecc., Purché non ambiguo per il lettore.
  • Il formato di output deve essere coerente:
    • Per input di tutti gli anni (ovvero, non è possibile generare nomi di mese per alcuni input e numeri di mese per altri input)
    • Oltre che coerente per output (ovvero, non è possibile eseguire l'output 1per Januarylo stesso output di Julper July)
    • Fondamentalmente, scegli un formato e attenersi ad esso.

Regole

  • Assumi il calendario gregoriano per input / output, anche fino a y = 1.
  • Gli anni bisestili devono essere adeguatamente contabilizzati (come promemoria: ogni anno divisibile per 4, tranne che per gli anni non divisibili per 100, a meno che non siano divisibili per 400 - 1700, 1800, 1900 non tutti gli anni bisestili, ma 2000 lo era).
  • È possibile utilizzare qualsiasi built-in o altri strumenti di calcolo della data che ti piace.
  • È accettabile un programma completo o una funzione. Se una funzione, è possibile restituire l'output anziché stamparlo.
  • Sono vietate le scappatoie standard .
  • Si tratta di quindi si applicano tutte le normali regole del golf e vince il codice più breve (in byte).

Esempi

   1 --> Apr, Dec
 297 --> May
1776 --> Sep
2000 --> Jan, Jul
2016 --> Feb, Oct
3385 --> Jan, Feb, Oct

Classifica



1
Correlati ma non duplicati o?
ElPedro,

@ElPedro Correlati ma non duplicati. Il primo non consente alcun built-in e chiede una combinazione data / giorno fissa (venerdì 13), mentre il secondo chiede l'ultima domenica di ogni mese dell'anno, limitata tra il 1900 e il 3015.
AdmBorkBork,

Siamo spiacenti @TimmD. Il mio fraintendimento del tuo commento.
ElPedro,

1
@ElPedro Nessun problema! Preferirei avere una domanda ed essere chiaro, piuttosto che non avere una domanda e avere qualcosa di poco chiaro.
AdmBorkBork,

Risposte:


2

Dyalog APL con dfns 's cal , Versione 15.0: 22; Versione 16.0: 19 byte

La funzione cal viene fornita con un'installazione predefinita, basta inserire )copy dfns.

Versione 15.0: ∊⎕{⍵/⍨2=≢⍎⊢⌿cal⍺⍵}¨⍳12

arruolarsi (appiattire)

⎕{... input numerico come argomento di sinistra alla seguente funzione anonima, prendendo a turno ciascuno dei valori del lato destro come argomento di destra

⍵/⍨ l'argomento if (fornisce un elenco vuoto in caso contrario)

2= due (vale a dire domenica e lunedì) è uguale a

il conteggio di

i numeri in

⊢⌿ la riga più in basso di

cal il calendario per

⍺⍵ anno argomento a sinistra, mese argomento a destra, quest'ultimo essendo

⍳12 Da 1 a 12

Versione 16.0: ⍸2=⎕{≢⍎⊢⌿cal⍺⍵}¨⍳12

gli indici dove

2= due uguali (vale a dire domenica e lunedì)

⎕{... input numerico come argomento di sinistra alla seguente funzione anonima, prendendo a turno ciascuno dei valori del lato destro come argomento di destra

il conteggio di

i numeri in

⊢⌿ la riga più in basso di

cal il calendario per

⍺⍵ anno argomento a sinistra, mese argomento a destra, quest'ultimo essendo

⍳12 Da 1 a 12


19

JavaScript (Firefox 30+), 112 109 103 95 byte

Guarda mamma, niente incorporati!

y=>[for(m of(i=0,y%4|y%400*!(y%100)&&6)+"63153042641")if((i++,y+(y>>2)-(y/100|0)*3/4|0)%7==m)i]

Ecco una versione ES6 a 107 byte:

y=>[...(y%4|y%400*!(y%100)&&6)+"63153042641"].map((m,i)=>(y+(y>>2)-(y/100|0)*3/4|0)%7-m?0:i+1).filter(x=>x)

Ed ecco il mio tentativo precedente, 123 113 byte di ES6:

y=>[(l=y%4|y%400*!(y%100))?[7]:[1,7],[4,12],[9],[3,6],[8,11],[5],l?[1,2,10]:[2,10]][(y+(y>>2)-(y/100|0)*3/4|0)%7]

Spiegazione

Il giorno della settimana di un determinato anno viene calcolato in questo modo:

y+(y>>2)-(y/100|0)*3/4|0)%7

In altre parole:

  • Prendi y.
  • Aggiungi il numero di 4 anni prima y( y>>2).
  • Sottrai il numero di 100 anni prima y( y/100|0).
  • Aggiungi di nuovo il numero di 400 anni prima y; questo è 1/4 di y/100|0, quindi usiamo *3/4|0.

Quindi moduliamo il risultato per 7. Se lasciamo 0dire domenica, 1significa lunedì, ecc., Il risultato corrisponde al giorno della settimana del 31 dicembre di quell'anno. Pertanto, per dicembre, vogliamo verificare se il risultato è 1. Questo ci dà l'ultimo carattere nella stringa.

L'ultimo giorno di novembre è 31 giorni prima dell'ultimo giorno di dicembre. Ciò significa che per l'ultimo giorno di novembre per essere un lunedì, il 31 dicembre deve essere un (1 + 31) % 7 = 4= giovedì.

Questa procedura si ripete fino al ritorno a marzo (a 3). Che ci sia o meno un giorno bisestile, l'ultimo giorno di febbraio è 31 giorni prima dell'ultimo giorno di marzo, quindi possiamo calcolare anche quello (è (3 + 31) % 7 = 6). La parte difficile è trovare il valore corretto per gennaio:

  • Se è un anno bisestile, l'ultimo giorno di gennaio è 29 giorni prima dell'ultimo giorno di febbraio, con il risultato (6 + 29) % 7 = 0.
  • Altrimenti, sono trascorsi 28 giorni dall'ultimo giorno di febbraio, con conseguente (6 + 28) % 7 = 6.

Possiamo calcolare se si tratta o meno di un anno bisestile con il seguente frammento:

!(y%400)|y%100*!(y%4)

Questo dà 0se ynon è un anno bisestile, e altrimenti un numero intero positivo. Questo ci porta a

!(y%400)|y%100*!(y%4)?0:6

per calcolare il giorno di gennaio. Tuttavia, possiamo fare di meglio invertendo le condizioni:

y%4|y%400*!(y%100)?6:0

Dato che il risultato della falsità è sempre 0, possiamo ridurlo a

y%4|y%400*!(y%100)&&6

salvando un altro byte prezioso.

Mettendo tutto insieme, eseguiamo il ciclo di ogni carattere nella stringa, controllando se ognuno è uguale al giorno della settimana del 31 dicembre. Manteniamo gli indici di quelli corrispondenti, restituendo questo array alla fine. Ed è così che fai i calcoli dell'anno bisestile senza built-in.


Owww ... Il mio cervello, hai rappresentato anni bisestili in tutto ciò?
Magic Octopus Urn,

2
@carusocomputing Ecco a cosa !(y%4)*y%100|!(y%400)serve. ogni anno divisibile per 4, tranne non anni divisibili per 100, a meno che non sia divisibile per 400
mbomb007

Spero y+(y>>2)+(z=y/25>>2)+(z>>2)che ti salvi ancora un byte.
Neil,

@Neil Grazie, ma ho trovato un modo migliore :-)
ETHproductions,

Bello; Ho salvato 6 byte sulla mia porta batch usando (y*5/4-(y/100)*3/4).
Neil,

11

JavaScript (Firefox 30-57), 67 65 64 63 61 61 byte

y=>[for(_ of(m='')+1e11)if(new Date(y+400,++m).getDay()==2)m]

Risparmiato 2 4 6 byte grazie a @ETHproductions. Ho salvato un altro byte emettendo i mesi in ordine inverso.


Penso che puoi salvare 2 byte alandandolo senza .keys():y=>[for(_ of(m=0,Array(12)))if(new Date(y+400,++m).getDay()==2)m]
ETHproductions

@ETHproductions Posso salvare un ulteriore byte invertendo l'ordine!
Neil,

L'ordine inverso va bene. La formattazione dell'output non è la parte interessante di questa sfida.
AdmBorkBork,

Qual è la nostra politica sulle comprensioni di array ora che sono state rimosse dalle specifiche?
MayorMonty,

Puoi salvare altri 2 byte saltando del Array(12)tutto: y=>[for(_ of(m=0,1e11+""))if(new Date(y+400,++m).getDay()==2)m]
ETHproductions

8

MySQL, 183 134 129 106 byte

SET @y=2016;SELECT help_topic_id AS m FROM mysql.help_topic HAVING m BETWEEN 1 AND 12 AND 2=DAYOFWEEK(LAST_DAY(CONCAT(@y,-m,-1)))

Sostituire 2016con l'anno desiderato. Correre.

Rev. 2: utilizzata la help_topicstabella nell'installazione predefinita invece di creare una tabella temporanea.

Rev.3: Adottato il trucco di aross- e ho notato che posso anche omettere le virgolette per "-1".
Tuttavia, -1è necessario in MySQL: ho bisogno di una data completa.

Rev.4: La restrizione m BETWEEN 1 AND 12può essere eseguita come m>0 AND m<13(-6), ma non è affatto necessaria: i valori non validi verranno ignorati; gli avvisi verranno conteggiati ma non elencati.


Hai davvero bisogno del tavolo shema mysql? mariadb.com/kb/en/mariadb/mysqlhelp_topic-table
Jörg Hülsermann

@ JörgHülsermann Non capisco.
Tito,

Dovrebbe FROM help_topicsenza mysql.lavoro? Non ci ho provato
Jörg Hülsermann,

@ JörgHülsermann solo se prependi USE mysql;Il database corretto deve essere selezionato in qualche modo.
Tito

5

Perl, 64 byte

Include +1 per -n

Dare input su STDIN:

perl -M5.010 mon.pl <<< 2016

mon.pl:

#!/usr/bin/perl -n
map$b.=$/.gmtime$_.e4,-7e6..3e7;say$b=~/on (\S+ )\S.* $_.* 1 /g

5

Lotto, 160 152 byte

@set/ay=%1,m=0,j=6*!(!(y%%4)*(y%%100)+(y%%400)),y=(y*5/4-y/100*3/4)%%7
@for %%d in (%j% 6 3 1 5 3 0 4 2 6 4 1)do @set/am+=1&if %%d==%y% call echo %%m%%

La risposta di Port of @ ETHproduction. Con abbreviazioni di mese per 197 189 byte:

@set/ay=%1,j=6*!(!(y%%4)*(y%%100)+(y%%400)),y=(y*5/4-y/100*3/4)%%7
@for %%m in (Jan.%j% Feb.6 Mar.3 Apr.1 May.5 Jun.3 Jul.0 Aug.4 Sep.2 Oct.6 Nov.4 Dec.1)do @if %%~xm==.%y% call echo %%~nm

4

J, 48 34 33 byte

[:I.(2=7|_2#@".@,@{.])&>@calendar

15 byte salvati con l'aiuto di @ Adám .

Utilizza il calendario incorporato per generare una matrice di stringhe che rappresentano i mesi, quindi analizza ciascuna stringa per determinare se l'ultimo lunedì è l'ultimo giorno del mese. Emette ogni mese come il numero del mese di ciascuno. Cioè, Jan = 0, Feb = 1, ..., Dec = 11.

L'output di calendarè

   _3 ]\ calendar 2016
┌─────────────────────┬─────────────────────┬─────────────────────┐
│         Jan         │         Feb         │         Mar         │
│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│
│                 1  2│     1  2  3  4  5  6│        1  2  3  4  5│
│  3  4  5  6  7  8  9│  7  8  9 10 11 12 13│  6  7  8  9 10 11 12│
│ 10 11 12 13 14 15 16│ 14 15 16 17 18 19 20│ 13 14 15 16 17 18 19│
│ 17 18 19 20 21 22 23│ 21 22 23 24 25 26 27│ 20 21 22 23 24 25 26│
│ 24 25 26 27 28 29 30│ 28 29               │ 27 28 29 30 31      │
│ 31                  │                     │                     │
├─────────────────────┼─────────────────────┼─────────────────────┤
│         Apr         │         May         │         Jun         │
│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│
│                 1  2│  1  2  3  4  5  6  7│           1  2  3  4│
│  3  4  5  6  7  8  9│  8  9 10 11 12 13 14│  5  6  7  8  9 10 11│
│ 10 11 12 13 14 15 16│ 15 16 17 18 19 20 21│ 12 13 14 15 16 17 18│
│ 17 18 19 20 21 22 23│ 22 23 24 25 26 27 28│ 19 20 21 22 23 24 25│
│ 24 25 26 27 28 29 30│ 29 30 31            │ 26 27 28 29 30      │
│                     │                     │                     │
├─────────────────────┼─────────────────────┼─────────────────────┤
│         Jul         │         Aug         │         Sep         │
│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│
│                 1  2│     1  2  3  4  5  6│              1  2  3│
│  3  4  5  6  7  8  9│  7  8  9 10 11 12 13│  4  5  6  7  8  9 10│
│ 10 11 12 13 14 15 16│ 14 15 16 17 18 19 20│ 11 12 13 14 15 16 17│
│ 17 18 19 20 21 22 23│ 21 22 23 24 25 26 27│ 18 19 20 21 22 23 24│
│ 24 25 26 27 28 29 30│ 28 29 30 31         │ 25 26 27 28 29 30   │
│ 31                  │                     │                     │
├─────────────────────┼─────────────────────┼─────────────────────┤
│         Oct         │         Nov         │         Dec         │
│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│
│                    1│        1  2  3  4  5│              1  2  3│
│  2  3  4  5  6  7  8│  6  7  8  9 10 11 12│  4  5  6  7  8  9 10│
│  9 10 11 12 13 14 15│ 13 14 15 16 17 18 19│ 11 12 13 14 15 16 17│
│ 16 17 18 19 20 21 22│ 20 21 22 23 24 25 26│ 18 19 20 21 22 23 24│
│ 23 24 25 26 27 28 29│ 27 28 29 30         │ 25 26 27 28 29 30 31│
│ 30 31               │                     │                     │
└─────────────────────┴─────────────────────┴─────────────────────┘

uso

   f =: [:I.(2=7|_2#@".@,@{.])&>@calendar
   f 1
3 11
   f 297
4
   f 1776
8
   f 2000
0 6
   f 2016
1 9
   f 3385
0 1 9

Spiegazione

[:I.(2=7|_2#@".@,@{.])&>@calendar  Input: year Y
                         calendar  Get 12 boxes each containing a month
    (                )&>@          Operate on each box
                    ]                Identity, get the box
         _2       {.                 Take the last two strings
                ,@                   Flatten it
             ".@                     Parse it into an array of integers
           #@                        Get the length
       7|                            Take it modulo 7
     2=                              Test if it equals 2 - it will either
                                     have two days or 9 days in the last
                                     two lines if the end is on a Monday
[:I.                               Return the indices containing a true value

aspetta, il calendario produce effettivamente arte ASCII?
Limone distruttibile

@DestructibleWatermelon Per essere esatti, il formato di output di calendarè un array di 12 box in cui ogni box contiene un array di 2d caratteri
miglia

Non so nemmeno come fare "ciascuno" in J, ma questo è già molto più breve: I.7=;#&.>".&.>,&.>_2{.&.>calendar 2016se combini tutti i "sotto-aperti" dovresti essere in grado di farlo abbastanza corto.
Adám,

@Adám Grazie, usa un metodo migliore ma non è un verbo in J. Penso che comunque aiuterà ancora
miglia

La mia intenzione era solo quella di ispirare. So che non è un verbo.
Adám,

4

Mathematica, 62 57 byte

DayName@DayRange[{#},{#+1},"EndOfMonth"]~Position~Monday&

Funzione anonima. Accetta un numero come input e restituisce un elenco di elenchi di numeri a elemento singolo come output. Sinceramente non sono più sicuro di come funzioni.


4

Perl + cal, 46 byte

say`cal $_ $ARGV[0]`=~/\n.{5}\n/&&$_ for 1..12

Esempio:

$ perl -E 'say`cal $_ $ARGV[0]`=~/\n.{5}\n/&&$_ for 1..12' 2016

2







10


$

1
A rigor di termini, questo è perl + cal, non solo perl :-p. Ad esempio, la mia macchina Windows ha perl, ma questo non funzionerà lì.
Filosofia,

Punto giusto, aggiornato questo e il mio tentativo bash.
steve,

4

Java 7,186 182 172 byte

Grazie a Kevin per aver salvato 4 byte
Grazie a @cliffroot per aver salvato 10 byte

int[]f(int n){int c=n-1,x=c*365+c/4+c/400-c/100,k=0,b[]={3,(n%4<1&n%100>0)|n%400<1?1:0,3,2,3,2,3,3,2,3,2,3},a[]=new int[12];for(int i:b)a[k++]=(x+=i+28)%7==1?1:0;return a;}

ungolfed

int[] f(int n) {
 int c=n-1,x=c*365+(c/4)+(c/400)-(c/100),k=0,
   b[] = {3,(n % 4 < 1 & n % 100 > 0) | n % 400 < 1 ? 1 : 0
                                     ,3,2,3,2,3,3,2,3,2,3},a = new int[ 12 ];

 if ( (n % 4 < 1 & n % 100 > 1) | n % 400 < 1 )
     b[ 1 ] = -1;
 for (int i : b)
    a[ k++ ] = (x += i + 28) % 7 == 1 ? 1 : 0;

return a;
     }

Questa versione è fornita da @cliffroot ( 168 byte )

 static int[] f(int n) {
 int b = 13561787 | ( (n%4 < 1 & n%100 > 0) | n%400 < 1 ? 1 << 20 : 0 ),
           x = --n*365 + n/4 + n/400 - n/100,a[]=new int[12],k=0;
    while (k < 12)
    a[k++] = (x += (b >> 24 - k*2&3 ) + 28) % 7 == 1 ? 1 : 0;
  return a;   }
    }

campione di output

1 1 0 0 0 0 0 0 0 1 0 0(for input 3385)

1
Dopo aver scritto la mia risposta sapevo che calcolare tutto da solo sarebbe stato più breve .. :) A proposito, puoi giocare n%4==0a golf n%4<1; n%400==0verso n%400<1e int c=...;int[]b=...,a=...verso int c=...,b[]=...,a[]=....
Kevin Cruijssen,

1
be apuò essere definito nella intparte in questo modo:int ... ,b[]=...,a[]=...
Olivier Grégoire,

1
int[]f(int n){int x=--n*365+n/4+n/400-n++/100,k=0,b[]={1,(n%4<1&n%100>0)|n%400<1?-1:-2,1,0,1,0,1,1,0,1,0,1},a[]=new int[12];for(int i:b)a[k++]=(x+=i+30)%7==1?1:0;return a;}pochi byte salvati
cliffroot,

1
può anche cambiare bper b[]={3,(n%4<1&n%100>0)|n%400<1?1:0,3,2,3,2,3,3,2,3,2,3}e i+30per i+28ulteriori 2 byte
cliffroot

1
e altri 3 byteint[]f(int n){int b=13561787|((n%4<1&n%100>0)|n%400<1?1<<20:0),x=--n*365+n/4+n/400-n/100,a[]=new int[12],k=0;while(k<12)a[k++]=(x+=(b>>24-k*2&3)+28)%7==1?1:0;return a;}
cliffroot,

3

Python 2, 100 byte

Ugh. La matematica con le date non è così semplice come vorrei.

lambda y:[m+1for m in range(12)if(date(y,12,31)if m>10else(date(y,m+2,1)-timedelta(1))).weekday()<1]

Provalo online

Stessa lunghezza:

lambda y:[m-1for m in range(2,14)if(date(y,12,31)if m>12else(date(y,m,1)-timedelta(1))).weekday()<1]

Non avrei nemmeno provato Python con questo. Bello sforzo.
ElPedro,

3

MATL , 21 byte

12:"G@QhO6(YO9XO77=?@

I mesi sono visualizzati come numeri.

Provalo online! Oppure verifica tutti i casi di test .

Spiegazione

Questo utilizza le funzioni integrate di conversione della data. Per l'anno dato verifica quale mese dell'ultimo giorno è lunedì.

Invece di specificare esplicitamente l'ultimo giorno del mese k(che può essere 28, 29, 30 o 31), specifichiamo il 0-th giorno del mese k+1, che è equivalente e non dipende dal mese o dall'anno.

12:      % Push [1 2 ... 12] (months)
"        % For each month k
  G      %   Push input
  @Q     %   Push k+1
  h      %   Concatenate
  O6(    %   Postpend four zeros. For example, for input 2016 and month k=1 
         %   (first iteration) this gives [2016 2 0 0 0 0] (year, month, day,
         %   hour, min, sec). The 0-th day of month k+1 is the same as the
         %   last day of month k.
  YO     %   Convert the above 6-element date vector to date number
  9XO    %   Convert date number to date string with output format 9, which 
         %   is weekday as a capital letter
  77=    %   Is it an 'M'?
  ?      %   If so
    @    %     Push current month (will be implicitly displayed)

3

Utilità Bash + GNU, 56 byte

seq -f1month-1day$1-%g-1 12|date -f- +%B%u|sed -n s/1//p

Sembra richiedere la dateversione 8.25. La versione 8.23 ​​in Ideone non la taglia.


3

Excel, 537 byte

Perché - sai - Excel!

Prende input anno in A1. Restituisce un elenco esadecimale di mesi; 1 = gennaio, C = dicembre. Poiché ogni mese è costituito da una sola cifra, non è necessario alcun separatore.

=IF(2=WEEKDAY(EOMONTH(DATE(A1,1,1),0)),1,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,2,1),0)),2,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,3,1),0)),3,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,4,1),0)),4,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,5,1),0)),5,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,6,1),0)),6,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,7,1),0)),7,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,8,1),0)),8,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,9,1),0)),9,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,10,1),0)),"A","")&IF(2=WEEKDAY(EOMONTH(DATE(A1,11,1),0)),"B","")&IF(2=WEEKDAY(EOMONTH(DATE(A1,12,1),0)),"C","")

Esempio: A1 contiene 2016. B1 contiene la formula sopra e viene visualizzato come 2A, che significa febbraio e ottobre.


3

PHP, 109 180 159 byte

for($z=$argv[1];$m++<12;)if(date(N,strtotime(sprintf("%04d-$m-",$z).cal_days_in_month(0,$m,$z)))<2)echo"$m,";
  • Produce l'anno fornito, non tutti (... leggi sempre la domanda)
  • Avvisi ignorati (grazie Titus)
  • Passa whilea forcome è ora un solo anno (di nuovo, grazie Titus)

Vecchio 2

$z=0;while($z++<9999){$o=[];$m=0;while($m++<12)if(date("N",strtotime(sprintf("%04d-$m-","$z").cal_days_in_month(0,$m,$z)))<2)$o[]=$m;echo count($o)>0?"$z:".implode(",",$o)."
":"";}

Supporta tutti gli anni dal punto al 10000, inoltre mi sono sbarazzato di un avviso var indefinito di cui non ero a conoscenza su un PC. Sì, è più lungo della vecchia versione, ma è più robusto.

Vecchio 1

while($z++<9999){$o=[];$m=0;while($m++<12)if(date("N",strtotime("$z-$m-".cal_days_in_month(0,$m,$z)))<2)$o[]=$m;echo count($o)>0?"$z:".implode(",",$o)."
":"";}

Se in esecuzione su Windows o un sistema a 32 bit ci sarà il temuto bug 2038, ma su un sistema Linux a 64 bit va bene.

Ho tentato di utilizzare ciò date("t"...che dovrebbe rappresentare l'ultima data di un determinato mese, ma i risultati non corrispondono a quelli precedentemente menzionati in questa discussione.


2
-2: "$ z" non ha bisogno di virgolette -7: ignora gli avvisi (non sono stampati con le impostazioni predefinite: non inizia $z, non ci sono virgolette per N) -1: forinvece di while -43 : accetta l' input come richiesto invece di scorrere negli anni -3: joininvece di implode-16: output diretto: for($z=$argv[1];$m++<12;)if(date(N,strtotime(sprintf("%04d-$m-",$z).cal_days_in_month(0,$m,$z)))<2)echo"$m,";+9 se insisti a non avere una virgola finale:echo$o=$o?",$m":$m;
Tito

Ahh ho letto male la domanda! Pensato che fosse per tutti gli anni .. oops: B Grazie anche per gli altri suggerimenti, ci arriveremo
CT14.IT

3

PHP, 92 byte

for($d=new DateTime("$argv[1]-1-1");$i++<12;)$d->modify("1month")->format(w)!=2?:print"$i,";

controllare 12 volte 1 mese dopo il primo giorno dell'anno è un martedì. Se è allora è il giorno prima dell'ultimo giorno del mese è un lunedì.


È possibile utilizzare l'eco anziché la stampa e salvare 1
Octopus il

1
@Octopus non all'interno dell'operatore ternario
Jörg Hülsermann,

3

C, 214 byte

main(int a,char *b[]){for(int x,y,d,m=12;m;m--){y=atoi(b[1]);x=m-1;d=x==1?(y%4==0?(y%100==0?(y%400==0?29:28):29):28):(x==3||x==5||x==10?30:31);if((d+=m<3?y--:y-2,23*m/9+d+4+y/4-y/100+y/400)%7==1)printf("%d\n",m);}}

Compilare

gcc -std=c99 -o foo foo.c

Ungolfed

Con crediti ai guru interessati.

Michael Keith e Tom Craver per il programma C per trovare il giorno della settimana data indicata .

Collin Biedenkapp per domande e risposte : Come posso capire qual è l'ultimo giorno del mese?

/* credit to Collin Biedenkapp */
short _get_max_day(short x, int z) {
    if(x == 0 || x == 2 || x == 4 || x == 6 || x == 7 || x == 9 || x == 11)
        return 31;
    else if(x == 3 || x == 5 || x == 8 || x == 10)
        return 30;
    else {
        if(z % 4 == 0) {
            if(z % 100 == 0) {
                if(z % 400 == 0)
                    return 29;
                return 28;
            }
            return 29;
        }
        return 28;
    }
}

main(int argc,char *argv[]) {
 for(int y,d,m=12;m;m--) {
  y=atoi(argv[1]);
  d=_get_max_day(m-1,y);
  /* credit to Michael Keith and Tom Craver */
  if ((d+=m<3?y--:y-2,23*m/9+d+4+y/4-y/100+y/400)%7 == 1)
    printf("%d\n",m);
 }
}

1
E se capovolgi ifl'altra direzione, per avere il tuo elseritorno 31e quindi puoi eliminare la grande ==catena?
AdmBorkBork,

1
sarebbe meglio se (x == 1) {z part} altro se (x == 3 || x == 5 || x == 8 || x == 10) restituisce 30 altrimenti restituisce 31
RosLuP

1
che dire: return x == 1? (z% 4 == 0? (z% 100 == 0? (z% 400 == 0? 29: 28): 29): 28) :( x == 3 | | x == 5 || x == 8 || x == 10? 30: 31)
RosLuP

TimmyD + RosLuP: grazie per i punti return (), 100 byte ora salvati.
steve

1
è possibile continuare a ridurre fino a questo punto: u (y, m) {return m-1? 30 + ((2773 >> m) & 1): 28+ (y% 4 == 0 && y% 100 || y% 400 == 0);} dove y è l'anno
em

3

C, 119 byte

t=1248700335,m;main(y){for(scanf("%d",&y),t+=y&3||y%25<1&&y&15;m++,(6+y+y/4-y/100+y/400+t)%7||printf("%d,",m),t;t/=7);}

Questo utilizza una tabella che contiene l'offset dei giorni della settimana dell'ultimo giorno di ogni mese per un anno bisestile, codificato in una parola firmata a 32 bit utilizzando la base 7. Se non è un anno bisestile, aggiungiamo 1 all'offset di gennaio (come vedi y&3||y%25<1&&y&15è usato per controllare per anni senza giorni bisestili). Quindi passiamo semplicemente in rassegna ogni mese e controlliamo se il suo ultimo giorno è un lunedì. Abbastanza semplice in realtà, niente brutti hack o trucchi. Qui è leggermente non golfato:

t=1248700335,m;
main(y){
  for(
    scanf("%d",&y),t+=y&3||y%25<1&&y&15;
    m++,(6+y+y/4-y/100+y/400+t)%7||printf("%d,",m),t;
    t/=7
  );
}

Potrei rivisitare questo per riscriverlo come una funzione per salvare alcuni caratteri. La printfprende anche un po 'troppo spazio ...


Printf ("% d,", m) stamperebbe qualcosa come 1, o 2, 3, quindi c'è sempre uno "," di più ... Preferisco usare solo spazi
RosLuP

In effetti, in realtà preferisco anche gli spazi nell'output, ma di solito scrivo le mie soluzioni C golfate in modo che non abbiano bisogno di spazi bianchi, quindi posso semplicemente nuotare tutto lo spazio bianco dalla mia versione semi-golfata quando voglio controllare il mio conteggio dei personaggi .
Fors,

3

PHP, 96 95 76 71 69 64 61 byte

Nota: i numeri degli anni devono essere riempiti con 4 caratteri, come 0070.

for(;13+$i-=1;)date(N,mktime(0,0,0,1-$i,0,$argn))-1||print$i;

Esegui in questo modo:

echo 3385 | php -nR 'for(;13+$i-=1;)date(N,mktime(0,0,0,1-$i,0,$argn))-1||print$i;';echo
> -1-2-10

Spiegazione

Iterati da -1 a -12. Crea data usando mktime, giorno 0(l'ultimo giorno del mese precedente) e mese 2..13. Formatta la data come numero del giorno e, se il risultato è 1, stampa il numero corrente. Il segno negativo -viene utilizzato come delimitatore.

Il Millenium Bug colpisce ancora!

Si noti che con questa versione, l'intervallo 0..100viene interpretato come 1970..2069. Questo non è un problema per l'intervallo 0..69, poiché le settimane hanno uno schema che si ripete ogni 400 anni (146097 giorni, esattamente 20871 settimane), ma per l'intervallo 70..99, 1900 viene aggiunto al numero dell'anno, che non è un multiplo di 400. Per risolvere quel problema SOLO per numeri di 30 anni in un intervallo di 10k, il modo più semplice è quello di aggiungere 400 al numero dell'anno per impedire l'interpretazione a 2 cifre ( +4 byte ):

for(;13+$i-=1;)date(N,mktime(0,0,0,1-$i,0,$argn+400))-1||print$i;

Ritocchi

  • Ho salvato un byte usando !~-$iper confrontare $icon 1( -1binario negato è 0, logicamente negato è true; ogni altro numero è false), quindi le parentesi non sono necessarie
  • Salvato 19 byte utilizzando la last day ofYYYY-mnotazione per creare la data
  • 5 byte salvati usando datee strtotimeinvece didate_create
  • Salvato 2 byte contando da numeri negativi, usando il segno negativo come delimitatore di output (non esistono numeri di mese negativi) e anche come delim nella YYYY-mparte della data
  • 5 byte salvati utilizzando mktimeinvece di strtotime. Ripristinato al giorno di utilizzo 0( mktimesupporta anche il mese 13, quindi 0-13== 31-12)
  • Salvato 3 byte utilizzando -Rper rendere $argndisponibile

mktimeelimina la necessità di riempire l'anno, no?
Tito,

@Titus, acuto. Beh, ho appena capito che mktimeè controintuitivo , perché gli argomenti sono presi come INTs. Ciò significa che non puoi trascinare l'anno ... quindi tutto nella gamma 0..100viene interpretato come 1970..2070. Questo non è un problema per l'intervallo 0..70perché 400 anni hanno un numero esatto di settimane (quindi i calendari ripetono lo schema ogni 400 anni), ma 70..99aggiunge 1900 (non un multiplo di 400!). Pertanto nuova ver. ha un bug.
circa il

L'unica soluzione che vedo in questo momento è $argv[1]+400... a meno che i giorni feriali di Julian e Gregorian non siano diversi.
Tito,

@Titus, sì. Regole dicono uso Gregoriana cal
aross

3

Excel, 428 97 96 byte

Ingresso in A1. Output valori esadecimali non separati (gennaio = 0, dicembre = B)

=IF(2=WEEKDAY(DATE(A1+2000,1,31)),0,"")&CHOOSE(WEEKDAY(DATE(A1+2000,3,0)),4,19,6,"3B",8,25,"7A")

Aggiunti 10 byte ("+2000") per consentire la gestione delle date precedenti al 1990.

Salvato 11 byte grazie a @ Engineer Toast .


Primo tentativo (428 byte), prendendo in prestito pesantemente dalla soluzione di @ Adám .

=IF(2=WEEKDAY(DATE(A1,1,31)),1,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,2,1),0)),2,"")&IF(2=WEEKDAY(DATE(A1,3,31)),3,"")&IF(2=WEEKDAY(DATE(A1,4,30)),4,"")&IF(2=WEEKDAY(DATE(A1,5,31)),5,"")&IF(2=WEEKDAY(DATE(A1,6,30)),6,"")&IF(2=WEEKDAY(DATE(A1,7,31)),7,"")&IF(2=WEEKDAY(DATE(A1,8,31)),8,"")&IF(2=WEEKDAY(DATE(A1,9,30)),9,"")&IF(2=WEEKDAY(DATE(A1,10,31)),"A","")&IF(2=WEEKDAY(DATE(A1,11,30)),"B","")&IF(2=WEEKDAY(DATE(A1,12,31)),"C","")

Come funziona anni prima del 1900? Il caso di test 297 -> Mayritorna 6con questa formula. Non dovrebbe essere 4? 17767Ainvece solo 8per settembre.
Ingegnere Toast,

Se riesci a farlo funzionare, tuttavia, probabilmente puoi usare Date(A1,3,0)invece diEOMONTH(DATE(A1,2,1),0)
Engineer Toast

2

Bash + cal, 58 byte

$ cat t.sh
for A in {1..12};do cal $A $1|grep -qx .....&&echo $A;done
$ bash t.sh 2016
2
10
$

+1: funziona con BSD cal(ad es. OSX), ma controlla gli spazi finali su GNU cal.
Trauma digitale

2

Python 2, 94 byte

from datetime import*
lambda y:[m for m in range(1,13)if date(y+(m>11),m%12+1,1).weekday()==1]

repl.it

Una funzione senza nome, richiede un anno intero, genera un elenco dei numeri dei mesi [1-12].

Ho anche provato a battere il conteggio dei byte con aritmetica senza successo (110 byte). :

lambda y:map(lambda x,v:(23*((x+2)%13or 1)/9+y-2*(0<x<11)+(x>10)+v/4-v/100+v/400)%7==4,range(12),[y-1]+[y]*11)

Una funzione senza nome che restituisce un elenco di valori booleani che rappresentano se i mesi [gennaio-dicembre] terminano in un lunedì


2

Java 7, 200 249 byte

import java.util.*;String c(int y){String r="";GregorianCalendar c=new GregorianCalendar();c.setGregorianChange(new Date(1L<<63));c.set(1,y);c.set(2,0);for(int i=0;i++<12;c.add(2,1)){c.set(5,c.getActualMaximum(5));if(c.get(7)==2)r+=i+" ";}return r;}

In Java, GregorianCalendarè un mix tra un calendario gregoriano e giuliano. Per questo motivo, l'anno ha 1dato risultati errati. Cambiare Calendar c=Calendar.getInstance();per GregorianCalendar c=new GregorianCalendar();c.setGregorianChange(new Date(1L<<63));risolvere questo problema forzando solo l'uso del calendario gregoriano. Grazie a @JonSkeet su stackoverflow.com per avermelo spiegato.

Codice non testato e test:

Provalo qui.

import java.util.*;
class M{
  static String c(int year){
    String r = "";
    GregorianCalendar calendar = new GregorianCalendar();
    calendar.setGregorianChange(new Date(Long.MIN_VALUE));
    calendar.set(Calendar.YEAR, year);
    calendar.set(Calendar.MONTH, 0);
    for(int i = 0; i++ < 12; calendar.add(Calendar.MONTH, 1)){
      calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE));
      if(calendar.get(Calendar.DAY_OF_WEEK) == 2){
        r += i+" ";
      }
    }
    return r;
  }

  public static void main(String[] a){
    System.out.println(c(1));
    System.out.println(c(297));
    System.out.println(c(1776));
    System.out.println(c(2000));
    System.out.println(c(2016));
    System.out.println(c(3385));
  }
}

Produzione:

4 12
5 
9 
1 7 
2 10 
1 2 10 

2

C # 6 C #, 171 167 135 byte

using System;
void d(int n){for(int i=0;++i<13;)if((int)new DateTime(n,i,DateTime.DaysInMonth(n,i)).DayOfWeek==1)Console.Write(i+" ");}

-32 byte grazie a Shebang

Stampa mesi come numeri; con spazio delimitato; con spazio finale. Ora questa risposta funziona anche per le versioni precedenti di C #.


Vecchio, 167 byte

using System;using System.Linq;
c(int n)=>string.Join(",",Enumerable.Range(1,12).Where(i=>new DateTime(n,i,DateTime.DaysInMonth(n,i)).DayOfWeek==(DayOfWeek)1));

-4 byte grazie a TimmyD

I mesi di output sono numeri nella stringa di restituzione, delimitati da virgole

Ungolfed

string c(int n)=>
    string.Join(",",                                        // Join them with commas
        Enumerable.Range(1,12)                              // For 1-12 inclusive
        .Where(                                             // Select only
            i=>new DateTime(n,i,DateTime.DaysInMonth(n,i)   // Get last day of that year-month
            ).DayOfWeek                                     // Get its day of week
            ==(DayOfWeek)1                              // Is Monday
        )
    )
;

@TimmyD Sì, ma è necessario un cast esplicito. Risposta aggiornata
Link ng

LINQ è divertente ma questo è 126 byte:; void q(int y){for(int m=1;m<13;m++){if((int)new DateTime(y,m,DateTime.DaysInMonth(y,m)).DayOfWeek==1){Console.WriteLine(m);}}}) Inoltre, sarebbe più breve lanciare il DayOfWeekto intdi quanto sarebbe lanciare il inttoDayOfWeek
Kade,

@Shebang Grazie. Non dovrei davvero giocare a golf in una riga Linq --- Solo Jon Skeet può farlo. Vedi se ho tempo per l'aggiornamento domani. Stanco adesso.
Link ng

È possibile convertire questo in un Action<int>per salvare alcuni byte
TheLethalCoder

2

Rubino, 54 + 6 = 60 byte

λ cat monday.rb
p (1..12).select{|m|Date.new($*[0].to_i,m,-1).monday?}
λ ruby -rdate monday.rb 2016
[2, 10]

6 byte per -rdatedalla riga di comando per ottenere la classe Date dalla libreria standard.

Spiegazione: piuttosto semplice grazie alla grande Dateclasse di Ruby stdlib . Non solo ha metodi come monday?, tuesday?ecc., Il costruttore prenderà numeri negativi per qualsiasi campo dell'anno scorso per significare "contare questo campo all'indietro dalla fine del periodo rappresentato dal campo precedente". $*è una scorciatoia per ARGV, quindi $*[0]è un modo rapido per ottenere il primo argomento della riga di comando.


2

PHP, 84 byte

for($m=1;$m++<14;){if(strftime('%w',strtotime($argv[1]."-$m-1"))==2)echo($m-1)." ";}

Il mio primo codice Golf. Questo è il PHP più breve finora su questa domanda.

EDIT: non sembra funzionare per l'anno 1. Dovrò capire perché, ma in questo momento devo andare.


1
Direi "Benvenuto in PPCG!" ma sei registrato qui da più tempo di me! : D Bel primo golf.
AdmBorkBork,

Il tuo errore è che crei 1-13-1 e 1-14-1 per l'anno 1 <13 è sufficiente. Se risolvi questo problema, puoi rimuovere le parentesi unnessary nel momento e pensare a usare l'operatore ternario
Jörg Hülsermann,

Ciò dovrebbe risolvere i tuoi problemifor(;$m++<12;)strftime("%w",strtotime($argv[1]+($m/12^0)."-".($m%12+1)."-1"))!=2?:print"$m ";
Jörg Hülsermann,

2

R, 106 99 95 83 78 77 74 byte

g=function(x)which(format(seq(as.Date(paste0(x,-2,-1)),,'m',12)-1,"%u")<2)

La sequenza degli ultimi giorni di ogni mese è data da seq(as.Date(paste0(x,-2,-1)),,'m',12)-1:

  • paste0costringe -2 e -1 ai caratteri. Se xera il 2016 per esempio, paste0(x,-2,-1)"2016-2-1"che viene convertito nel 1 febbraio 2016 entro as.Date.

  • seqapplicato a un POSIXct o un oggetto Date è seq(from, to , by, length.out): qui tonon viene dato, byviene dato come 'm'abbinato 'month'grazie alla corrispondenza parziale ed length.outè ovviamente 12.

  • La sequenza risultante è il primo giorno dei 12 mesi a partire da febbraio dell'anno in questione. -1ci dà quindi l'ultimo giorno dei 12 mesi a partire da gennaio dell'anno in questione.

Casi test:

> g(1)
[1]  4 12
> g(25)
[1] 3 6
> g(297)
[1] 5
> g(2000)
[1] 1 7
> g(2016)
[1]  2 10
> g(3385)
[1]  1  2 10
> g(9999)
[1] 5

Vecchia versione a 95 byte, che mostra i nomi dei mesi anziché solo i loro numeri:

g=function(x)format(S<-seq(as.Date(sprintf("%04i-02-01",x)),,'m',12)-1,"%B")[format(S,"%u")==1]

Questa risposta è semplicemente geniale. Non avevo idea di seqavere un metodo per gli Dateoggetti e questo risolve il problema di as.Datenon gestire gli anni precedenti 10000nella mia risposta eliminata.
Billywob,

@Billywob sì seq.Datee seq.POSIXtsono piuttosto impressionanti: possono persino elaborare comandi come seq(time1, time2, by="10 min")o seq(date1, date2, by="quarter"). Molto utile quando si traccia una serie temporale.
plannapus,

2

Japt, 24 byte

Do1 £Ov"Ð400+U"+X e ¥2©X

Provalo online! Emette una serie di numeri, confalseal posto di mesi che non finiscono in un lunedì.

Nell'interprete c'era un bug che non mi permetteva di usare Ðnel corpo della funzione £. Dopo la correzione di bug e un'altra aggiunta di funzionalità, si tratta di 18 byte nel commit corrente:

Do1@Ð400+UX e ¥2©X

1

Java, 143 129 byte

Questo utilizza la nuova API time di Java 8.

y->{String s="";for(int m=0;++m<13;)if(java.time.YearMonth.of(y,m).atEndOfMonth().getDayOfWeek().ordinal()==0)s+=m+" ";return s;}

Produzione

Si noti che ogni riga ha uno spazio extra alla fine.

4 12 
5 
9 
1 7 
2 10 
1 2 10 

Ungolfed e test

import java.time.*;
import java.util.function.*;

public class Main {
    public static void main (String[] args) {
        IntFunction<String> func = year -> {
          String result = "";
          for (int month=1; month <= 12; month++) {
            if (YearMonth.of(year, month).atEndOfMonth().getDayOfWeek().ordinal() == 0) {
              result += month + " ";
            }
          }
          return result;
        };
        System.out.println(func.apply(1));
        System.out.println(func.apply(297));
        System.out.println(func.apply(1776));
        System.out.println(func.apply(2000));
        System.out.println(func.apply(2016));
        System.out.println(func.apply(3385));
    }
}

rade

  1. Da 143 a 129 byte: usare DayOfWeek::ordinalper confrontare con una costante numerica invece della costante enum.
    Grazie @TimmyD per l'idea generale se non la soluzione esatta! ;-)

@TimmyD purtroppo, è un enum. Ha un getValue()metodo, tuttavia, che salverebbe alcuni byte.
Celos,

@Celos ordinal()risparmia 1 byte in più rispetto a getValue(), anche se si suggerisce di non usarlo mai.
Olivier Grégoire,

si, buon pensiero. Ho pubblicato il mio commento senza primo aggiornamento, quindi non ho visto la tua risposta e modifica.
Celos,

1

GNU awk, 80 byte

{for(;m<13;a=mktime($0" "++m" 1 9 0 0")){if(strftime("%w",a-8e4)~1){print m-1}}}

Esempio

$ gawk '{for(;m<13;a=mktime($0" "++m" 1 9 0 0")){if(strftime("%w",a-8e4)~1){print m-1}}}' <<<2016
2
10
$
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.