Последний понедельник

27

Понедельник, 31 октября, Хэллоуин. И это заставило меня задуматься - интересно, в какие другие месяцы последний день месяца тоже будет понедельником?

вход

  • Целое положительное число в любом удобном формате, представляющее год 10000 > y > 0.
  • Ввод можно дополнить нулями (например, 0025для года 25), если требуется.

Выход

  • Список месяцев того года, где последний день месяца - понедельник.
  • Это могут быть названия месяцев (например, January, March, October), или короткие имена ( Jan, Mar, Oct), или числа ( 1, 3, 10), отдельные строки, или список, или разделители, и т. Д., Только если это однозначно для читателя.
  • Формат вывода должен быть согласованным:
    • Для ввода всех лет (то есть, вы не можете выводить названия месяцев для некоторых входов и номера месяцев для других входов)
    • Так же как непротиворечиво для каждого выхода (то есть вы не можете выводить 1для Januaryтого же вывода, что и Julдля July)
    • В основном, выберите один формат и придерживайтесь его.

правила

  • Предположим, Григорианский календарь для ввода / вывода, даже до y = 1.
  • Високосные годы должны быть должным образом учтены (в качестве напоминания: каждый год делится на 4, кроме не делимых на 100 лет, если не делится также на 400 - 1700, 1800, 1900 - все не были високосными, но 2000 год был).
  • Вы можете использовать любые встроенные или другие инструменты расчета даты, которые вам нравятся.
  • Допустимы либо полная программа, либо функция. Если функция, вы можете вернуть вывод, а не распечатать его.
  • Стандартные лазейки запрещены.
  • Это поэтому применяются все обычные правила игры в гольф, и выигрывает самый короткий код (в байтах).

Примеры

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

Leaderboard

AdmBorkBork
источник
1
Связанные, но не дубликаты или?
ElPedro
@ElPedro Связанные, но не дубликаты. Первый не допускает никаких встроенных функций и запрашивает комбо с фиксированной датой / днем ​​(пятница, 13-е), а второй запрашивает последнее воскресенье каждого месяца в году, ограниченное между 1900 и 3015.
AdmBorkBork
Извините @TimmD. Мое недопонимание вашего комментария.
ElPedro
1
@ElPedro Нет проблем! Я предпочел бы, чтобы у меня был вопрос, и чтобы он был ясным, чем не иметь вопроса и иметь что-то непонятное.
AdmBorkBork

Ответы:

2

Dyalog АПЗ с dfns «ы кал , версия 15.0: 22; Версия 16.0: 19 байт

Функция cal поставляется с установкой по умолчанию, просто введите )copy dfns.

Версия 15.0: ∊⎕{⍵/⍨2=≢⍎⊢⌿cal⍺⍵}¨⍳12

подключить

⎕{... числовой ввод в качестве левого аргумента для следующей анонимной функции, принимая каждое правое значение в качестве правого аргумента по очереди

⍵/⍨ аргумент if (дает пустой список, если нет)

2= два (а именно воскресенье и понедельник) равно

подсчет

числа в

⊢⌿ самый нижний ряд

cal календарь для

⍺⍵ год левый аргумент, месяц правый аргумент, последний является

⍳12 От 1 до 12

Версия 16.0: ⍸2=⎕{≢⍎⊢⌿cal⍺⍵}¨⍳12

индексы где

2= два равных (а именно воскресенье и понедельник)

⎕{... числовой ввод в качестве левого аргумента для следующей анонимной функции, принимая каждое правое значение в качестве правого аргумента по очереди

подсчет

числа в

⊢⌿ самый нижний ряд

cal календарь для

⍺⍵ год левый аргумент, месяц правый аргумент, последний является

⍳12 От 1 до 12

Адам
источник
19

JavaScript (Firefox 30+), 112 109 103 95 байт

Смотри, мама, никаких встроенных модулей!

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]

Вот 107-байтовая версия ES6:

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)

И вот моя предыдущая попытка, 123 113 байтов 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]

объяснение

День недели определенного года рассчитывается так:

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

Другими словами:

  • Возьми y.
  • Добавьте число 4-х лет до y( y>>2).
  • Вычтите число сотых лет до y( y/100|0).
  • Добавьте обратно в число 400-летних ранее y; это 1/4 от y/100|0, поэтому мы используем *3/4|0.

Затем мы модулируем результат на 7. Если мы допустим 0среднее воскресенье, 1средний понедельник и т. Д., Результат соответствует дню недели 31 декабря этого года. Поэтому за декабрь мы хотим проверить, есть ли результат 1. Это дает нам последний символ в строке.

Последний день ноября - 31 день до последнего дня декабря. Это означает, что для последнего дня ноября, который будет понедельником, 31 декабря должно быть (1 + 31) % 7 = 4= четверг.

Эта процедура повторяется, пока мы не вернемся к марту (а 3). Независимо от того, существует ли високосный день, последний день февраля на 31 день раньше последнего дня марта, так что мы можем рассчитать это тоже (3 + 31) % 7 = 6. Сложная часть находит правильное значение для января:

  • Если это високосный год, последний день января - 29 дней до последнего дня февраля, в результате чего (6 + 29) % 7 = 0.
  • В противном случае до последнего дня февраля остается 28 дней, что приводит к (6 + 28) % 7 = 6.

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

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

Это дает, 0если yне високосный год, и положительное целое число в противном случае. Это приводит нас к

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

для расчета дня января. Тем не менее, мы можем добиться большего, изменив условия:

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

Так как ложный результат всегда равен 0, мы можем уменьшить его до

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

сохранение еще одного драгоценного байта.

Собирая все это вместе, мы перебираем каждый символ в строке, проверяя, равен ли каждый день недели 31 декабря. Мы сохраняем индексы, которые совпадают, возвращая этот массив в конце. И именно так вы делаете расчеты високосного года без встроенных модулей.

ETHproductions
источник
Оуууу ... Мой мозг, тебе приходилось подсчитывать високосные годы?
Волшебная Осьминога Урна
2
@carusocomputing Вот для чего !(y%4)*y%100|!(y%400). каждый год делится на 4, кроме не делимых на 100 лет, если не делится также на 400
mbomb007
Надеюсь, y+(y>>2)+(z=y/25>>2)+(z>>2)все еще экономит вам байт.
Нил
@Neil Спасибо, но я нашел лучший способ :-)
ETHproductions
Ницца; Я сохранил 6 байтов на моем пакетном порту, используя (y*5/4-(y/100)*3/4).
Нил
11

JavaScript (Firefox 30-57), 67 65 64 63 61 байт

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

Сохранено 2 4 6 байт благодаря @ETHproductions. Сохраняет еще один байт, выводя месяцы в обратном порядке.

Нил
источник
Я думаю, что вы можете сэкономить 2 байта, выполняя его без .keys():y=>[for(_ of(m=0,Array(12)))if(new Date(y+400,++m).getDay()==2)m]
ETHproductions
@ETHproductions Я могу сохранить еще один байт, изменив порядок!
Нил
Обратный порядок в порядке. Форматирование вывода не является интересной частью этой проблемы.
AdmBorkBork
Какова наша политика в отношении массивов теперь, когда они были удалены из спецификации?
MayorMonty
Вы можете сэкономить еще 2 байта, пропустив Array(12)всего: y=>[for(_ of(m=0,1e11+""))if(new Date(y+400,++m).getDay()==2)m]
ETHproductions
8

MySQL, 183 134 129 106 байт

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

Замените 2016на нужный год. Запустить.

Версия 2: Использовал help_topicsтаблицу в установке по умолчанию вместо создания временной таблицы.

Откр.3- : принял трюк Аросса и заметил, что я также могу опустить кавычки "-1".
Тем не менее, -1требуется в MySQL: мне нужна полная дата.

Rev.4: ограничение m BETWEEN 1 AND 12может быть сделано как m>0 AND m<13(-6), но не нужно вообще - недопустимые значения будут игнорироваться; предупреждения будут учтены, но не перечислены.

Titus
источник
Тебе нужен действительно стол Shema MySQL? mariadb.com/kb/en/mariadb/mysqlhelp_topic-table
Йорг Хюльсерманн
@ JörgHülsermann Я не понимаю твою точку зрения.
Тит
Должен FROM help_topicбез mysql.работы? Я не пробовал
Йорг Хюльсерманн
@ JörgHülsermann только в том случае, если вы предварительно добавите USE mysql;правильную базу данных.
Тит
5

Perl, 64 байта

Включает +1 для -n

Внесите свой вклад в 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

Пакетное, 160 152 байта

@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%%

Порт @ ETHproduction ответа. С месячными сокращениями за 197 189 байт:

@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 байта

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

Сохранено 15 байт с помощью @ Adám .

Использует встроенный календарь для генерации массива строк, представляющих месяцы, а затем анализирует каждую строку, чтобы определить, является ли последний понедельник последним днем ​​месяца. Он выводит каждый месяц как номер месяца каждого. То есть Jan = 0, Feb = 1, ..., Dec = 11.

Выход 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               │                     │                     │
└─────────────────────┴─────────────────────┴─────────────────────┘

использование

   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

объяснение

[: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
миль
источник
подождите, календарь действительно выводит ascii art?
Разрушаемый лимон
@DestructibleWatermelon Если быть точным, выходной формат calendarпредставляет собой массив из 12 блоков, каждый из которых содержит двумерный массив символов
мили
Я даже не знаю, как сделать «каждый» в J, но это уже намного короче: I.7=;#&.>".&.>,&.>_2{.&.>calendar 2016если вы объедините все «недостаточно открытые», вы сможете получить его довольно коротким.
Адам
@ Adám Спасибо, он использует лучший метод, но это не глагол в J. Я думаю, что это все равно поможет
мили
Мое намерение было только вдохновлять. Я знаю, что это не глагол.
Адам
4

Mathematica, 62 57 байт

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

Анонимная функция. Принимает число в качестве ввода и возвращает список одноэлементных списков чисел в качестве вывода. Я, честно говоря, сам не уверен, как это работает.

LegionMammal978
источник
4

Perl + cal, 46 байт

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

Пример:

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

2







10


$
Стив
источник
1
Строго говоря, это perl + cal, а не только perl :-p. Например, на моей машине с Windows есть Perl, но это не сработает.
Philomory
Честно, обновил это и мою попытку bash.
Стив
4

Java 7,186 182 172 байта

Спасибо Кевину за сохранение 4 байта
Спасибо @cliffroot за сохранение 10 байтов

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

Эта версия предоставлена @cliffroot ( 168 байт )

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

выходной образец

1 1 0 0 0 0 0 0 0 1 0 0(for input 3385)
Numberknot
источник
1
После того, как я написал свой ответ , который я знал , что все вычисления сам будет короче .. :) Кстати, вы можете играть в гольф , n%4==0чтобы n%4<1; n%400==0к n%400<1и int c=...;int[]b=...,a=...к int c=...,b[]=...,a[]=....
Кевин Круйссен
1
bи aможет быть определено в intчасти, как это:int ... ,b[]=...,a[]=...
Оливье Грегуар
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;}сохранено несколько байтов
Cliffroot
1
можно также изменить , bчтобы b[]={3,(n%4<1&n%100>0)|n%400<1?1:0,3,2,3,2,3,3,2,3,2,3}и i+30в i+28течение более 2 байта
cliffroot
1
и еще 3 байта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;}
клиффрут
3

Python 2, 100 байт

Тьфу. Математика с датами не так проста, как хотелось бы.

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]

Попробуйте онлайн

Одинаковая длина:

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]
mbomb007
источник
Я даже не собирался пробовать Python с этим. Хорошее усилие.
ElPedro
3

MATL , 21 байт

12:"G@QhO6(YO9XO77=?@

Месяцы отображаются в виде чисел.

Попробуйте онлайн! Или проверьте все тестовые случаи .

объяснение

Это использует встроенные функции преобразования даты. Для данного года он проверяет, какой из последних дней месяца - понедельник.

Вместо того, чтобы явно указывать последний день месяца k(который может быть 28, 29, 30 или 31), мы указываем 0-й день месяца k+1, который эквивалентен и не зависит от месяца или года.

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

Утилиты Bash + GNU, 56 байт

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

Похоже, требуется dateверсия 8.25. Версия 8.23 ​​в Ideone не режет его.

Цифровая травма
источник
3

Excel, 537 байт

Потому что - вы знаете - Excel!

Вводит год в А1. Возвращает шестнадцатеричный список месяцев; 1 = январь, C = декабрь. Поскольку каждый месяц представляет собой одну цифру, разделитель не требуется.

=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","")

Пример: A1 содержит 2016. B1 содержит приведенную выше формулу и отображается как 2A, означая февраль и октябрь.

Адам
источник
3

PHP, 109 180 159 байт

for($z=$argv[1];$m++<12;)if(date(N,strtotime(sprintf("%04d-$m-",$z).cal_days_in_month(0,$m,$z)))<2)echo"$m,";
  • Выводит указанный год, а не все (... всегда читайте вопрос)
  • Проигнорированные уведомления (спасибо Титус)
  • Перейдите whileна forодин год (спасибо Титу)

Старый 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)."
":"";}

Поддерживает все годы от точки до 10000, также избавился от неопределенного предупреждения о переменном токе, о котором я не знал ни на одном ПК. Да, он длиннее старой версии, но он более надежный.

Старый 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)."
":"";}

При работе в Windows или 32-битной системе будет страшная ошибка 2038, но в 64-битной системе Linux это нормально.

Я пытался использовать, date("t"...который должен представлять последнюю дату данного месяца, но результаты не совпадали с ранее упомянутыми в этой теме.

CT14.IT
источник
2
-2: «$ z» не нуждается в кавычках -7: игнорировать уведомления (они не распечатываются с настройками по умолчанию: не инициализировать $z, кавычек нет N) -1: forвместо while -43 : принимать ввод по запросу, а не проходить по годам -3: joinвместо implode-16: прямой вывод: 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, если вы настаиваете на отсутствии запятой:echo$o=$o?",$m":$m;
Тит
Ааа, неправильно понял вопрос! Думал, что это было в течение всех лет .. упс: B Спасибо за другие предложения, также получу их
CT14.IT
3

PHP, 92 байта

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

проверка 12 раз 1 месяц после первого дня года - вторник. Если это так, то это день до того, как последний день месяца является понедельником.

Йорг Хюльсерманн
источник
Вы можете использовать эхо вместо печати и сохранить 1
Octopus
1
@ Осьминог не внутри троичного оператора
Йорг Хюльсерманн
3

C 214 байта

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

Compile

gcc -std=c99 -o foo foo.c

Ungolfed

С кредитами соответствующих гуру.

Майкл Кит и Том Крейвер для C Program, чтобы найти день недели с заданной датой .

Collin Biedenkapp для Q & A: Как мне определить, какой последний день месяца?

/* 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
Что, если вы перевернете ifв другом направлении, чтобы получить свое elseвозвращение 31, и, следовательно, вы можете устранить большую ==цепь?
AdmBorkBork
1
было бы лучше, если (x == 1) {z part} else, если (x == 3 || x == 5 || x == 8 || x == 10), вернем 30, вернем 31
RosLuP
1
а как насчет возврата 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)
РосЛюП
TimmyD + RosLuP: спасибо за точки возврата (), теперь сохранено 100 байт.
Стив
1
можно продолжать сокращать, наконец, до этого: u (y, m) {return m-1? 30 + ((2773 >> m) & 1): 28+ (y% 4 == 0 && y% 100 || y% 400 == 0);} где y - год, а m месяц
РосЛюП,
3

C 119 байтов

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

При этом используется таблица, которая содержит смещение дней недели последнего дня каждого месяца для високосного года, закодированное в 32-разрядном слове со знаком с использованием базы 7. Если это не високосный год, мы добавляем 1 к смещению января (как видите y&3||y%25<1&&y&15, используется для проверки на годы без високосных дней). Затем мы просто перебираем каждый месяц и проверяем, является ли его последний день понедельником. На самом деле все просто, никаких уродливых хаков или уловок. Вот это немного разглажено:

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

Я мог бы вернуться к этому, чтобы переписать его как функцию, чтобы сохранить несколько символов. printfТакже занимает немного слишком много места ...

Форс
источник
Printf ("% d,", m) будет печатать что-то как 1 или 2, 3, поэтому всегда есть один ',' больше ... Я предпочитаю использовать только пробелы
RosLuP
На самом деле, я также предпочитаю пробелы в выводе, но я обычно пишу свои решения C для игры в гольф, чтобы им не требовалось пробелов, поэтому я могу просто обнулить все пробелы в моей версии для игры в пол-гольфа, когда я хочу проверить количество персонажей ,
Форс
3

PHP, 96 95 76 71 69 64 61 байт

Примечание: номера года должны быть дополнены до 4 символов, как 0070.

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

Запустите так:

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

объяснение

Итерирует от -1 до -12. Создайте дату, используя mktime, день 0(последний день предыдущего месяца) и месяц 2..13. Отформатируйте дату как число дня , и если результат равен 1, напечатайте текущий номер. Отрицательный знак -используется в качестве разделителя.

«Тысячелетний жук» снова наносит удар!

Обратите внимание, что в этой версии диапазон 0..100интерпретируется как 1970..2069. Это не проблема для диапазона 0..69, поскольку недели имеют схему, которая повторяется каждые 400 лет (146097 дней, ровно 20871 неделя), но для диапазона 70..99к номеру года добавляется 1900, который не кратен 400. Исправить эта проблема ТОЛЬКО для 30-летних чисел в диапазоне 10 КБ, самый простой способ - добавить 400 к номеру года, чтобы предотвратить двухзначную интерпретацию ( +4 байта ):

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

Tweaks

  • Сохраненное байты, используя !~-$iдля сравнения $iс 1( -1двоичным инвертированным является 0логически сведен на нет это true; любой другой номер false), поэтому круглые скобки не нужны
  • Сохранено 19 байт с использованием last day ofYYYY-mнотации для создания даты
  • Сохранено 5 байт с использованием dateи strtotimeвместоdate_create
  • Сохранение 2 байтов путем подсчета отрицательных чисел, использования отрицательного знака в качестве выходного разделителя (отрицательных чисел месяца не существует), а также в качестве разделителя в YYYY-mчасти даты
  • Сохранено 5 байтов при использовании mktimeвместо strtotime. Вернулся к использованию дня 0( mktimeтакже поддерживает 13 месяцев, поэтому 0-13== 31-12)
  • Сохранено 3 байта с помощью, -Rчтобы сделать $argnдоступным
aross
источник
mktimeустраняет необходимость дополнять год, не так ли?
Тит
@ Титус, острый. Ну, я просто понял, что mktimeэто нелогично , потому что аргументы принимаются за INTs. Это означает, что вы не можете определить год ... так что все в диапазоне 0..100интерпретируется как 1970..2070. Это не проблема для диапазона, 0..70потому что 400 лет имеют точное количество недель (поэтому календари повторяют шаблон каждые 400 лет), но 70..99добавляют 1900 (не кратно 400!). Поэтому новая версия есть ошибка
aross
Единственное решение, которое я вижу для этого сейчас, это $argv[1]+400... если только не различаются будни по Юлиану и Григорианскому
Тит
@ Титус, да. Правила говорят , использование григорианского кал
aross
3

Excel, 428 97 96 байт

Ввод в А1. Вывести неразделенные шестнадцатеричные значения (январь = 0, декабрь = B)

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

Добавлены 10 байтов ("+2000") для обработки дат до 1990 года.

Сохранено 11 байт благодаря @ Engineer Toast .


Первая попытка (428 байт), в значительной степени заимствованная из решения @ 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","")
Wernisch
источник
Как это работает на годы раньше, чем 1900? Тестовый пример 297 -> Mayвозвращается 6с этой формулой. Разве это не должно быть 4? 1776дает 7Aвместо только 8на сентябрь.
Инженер Тост
Если вы заставите его работать, вы можете использовать Date(A1,3,0)вместо этогоEOMONTH(DATE(A1,2,1),0)
Engineer Toast
2

Bash + cal, 58 байт

$ cat t.sh
for A in {1..12};do cal $A $1|grep -qx .....&&echo $A;done
$ bash t.sh 2016
2
10
$
Стив
источник
+1 - работает для BSD cal(например, OSX), но следите за пробелами в GNU cal.
Цифровая травма
2

Python 2, 94 байта

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

Функция без имени, принимает целочисленный год, выводит список номеров месяцев [1-12].

Я также безуспешно пытался побить число байтов с помощью арифметики (110 байт). :

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)

Безымянная функция, которая возвращает список логических значений, представляющих, если месяцы [январь-декабрь] заканчиваются в понедельник

Джонатан Аллан
источник
2

Java 7, 200 249 байт

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

В Java GregorianCalendarэто смесь григорианского и юлианского календаря. Из-за этого год 1дал неверные результаты. Изменение Calendar c=Calendar.getInstance();в GregorianCalendar c=new GregorianCalendar();c.setGregorianChange(new Date(1L<<63));это исправлено, заставляя использовать только по григорианскому календарю. Спасибо @JonSkeet на stackoverflow.com за объяснение этого мне.

Ungolfed & тестовый код:

Попробуй это здесь.

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

Выход:

4 12
5 
9 
1 7 
2 10 
1 2 10 
Кевин Круйссен
источник
2

C # 6 C #, 171 167 135 байтов

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 байта благодаря Шебангу

Печатать месяцы как числа; с пробелами; с замыкающим пространством. Теперь этот ответ также работает для более ранних версий C #.


Старый, 167 байт

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 байта благодаря TimmyD

Выходные месяцы - это числа в возвращаемой строке, разделенные запятой

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
        )
    )
;
Ссылка Ng
источник
@TimmyD Да, но нужно явное приведение. Ответ обновлен
ссылка Ng
LINQ - это весело, но это 126 байтов:; 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);}}}) Кроме того, было бы короче разыграть DayOfWeekto, intчем это было бы разыграть inttoDayOfWeek
Kade
@Shebang Спасибо. Я действительно не должен играть в гольф в одну линию linq --- Только Джон Скит может сделать это. Посмотрим, успею ли я завтра обновить. Устали сейчас.
Ссылка Ng
Вы можете преобразовать это, Action<int>чтобы сохранить некоторые байты
TheLethalCoder
2

Рубин, 54 + 6 = 60 байт

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

6 байтов -rdateв командной строке для получения класса Date из стандартной библиотеки.

Объяснение: довольно просто благодаря отличному Dateклассу Ruby stdlib . Мало того, что он имеет такие методы, как monday?, tuesday?и т. Д., Конструктор будет принимать отрицательные числа для любого поля в прошлом году, что означает «считать это поле в обратном направлении от конца периода, представленного предыдущим полем». $*это сокращение от ARGV, так $*[0]что это быстрый способ получить первый аргумент командной строки.

philomory
источник
2

PHP, 84 байта

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

Мой первый Код Гольф. Это самый короткий PHP на данный момент по этому вопросу.

РЕДАКТИРОВАТЬ: кажется, не работает в течение года. Я должен выяснить, почему, но сейчас я должен идти.

Осьминог
источник
1
Я бы сказал "Добро пожаловать в PPCG!" но вы были зарегистрированы здесь дольше, чем я! : D Хороший первый гольф.
AdmBorkBork
Ваша ошибка в том, что вы создаете 1-13-1 и 1-14-1 для года 1 <13 достаточно. Если вы решите это, вы можете убрать лишние скобки и подумать об использовании троичного оператора
Йорг Хюльсерманн,
Это должно исправить ваши проблемыfor(;$m++<12;)strftime("%w",strtotime($argv[1]+($m/12^0)."-".($m%12+1)."-1"))!=2?:print"$m ";
Йорг Хюльсерманн
2

R, 106 99 95 83 78 77 74 байта

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

Последовательность последних дней каждого месяца определяется как seq(as.Date(paste0(x,-2,-1)),,'m',12)-1:

  • paste0принуждает -2 и -1 к символам. Если xбыл, например, 2016, т. Д., paste0(x,-2,-1)Которые "2016-2-1"затем конвертируются в 1 февраля 2016 года as.Date.

  • seqприменяется к объекту POSIXct или Date seq(from, to , by, length.out): здесь toэто не дано, byдано как 'm'сопоставляемое 'month'благодаря частичному сопоставлению и, length.outконечно, 12.

  • Результирующая последовательность - это первый день 12 месяцев, начиная с февраля рассматриваемого года. -1дает нам последний день из 12 месяцев, начиная с января соответствующего года.

Тестовые случаи:

> 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

Старая версия на 95 байтов, выводящая названия месяцев, а не только их числа:

g=function(x)format(S<-seq(as.Date(sprintf("%04i-02-01",x)),,'m',12)-1,"%B")[format(S,"%u")==1]
plannapus
источник
Этот ответ просто блестящий. Я понятия не seqимел, что у Dateменя есть метод для -объектов, и это решает проблему as.Dateотсутствия обработки годами выше 10000в моем удаленном ответе.
Billywob
@Billywob да seq.Dateи seq.POSIXtвпечатляют: они могут даже обрабатывать такие команды, как seq(time1, time2, by="10 min")или seq(date1, date2, by="quarter"). Очень полезно при построении временных рядов.
plannapus
2

Japt, 24 байта

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

Проверьте это онлайн! Выводит массив чисел сfalseмесяцами, которые не заканчиваются в понедельник.

В интерпретаторе была ошибка, которая не позволяла мне использовать Ðтело функции £. После исправления ошибки и добавления другой функции это составляет 18 байт в текущем коммите:

Do1@Ð400+UX e ¥2©X
ETHproductions
источник
1

Java, 143 129 байт

Это использует новый API времени 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;}

Выход

Обратите внимание, что каждая строка имеет дополнительный пробел в конце.

4 12 
5 
9 
1 7 
2 10 
1 2 10 

Неуправляемый и тестирующий

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

Бритвы

  1. От 143 до 129 байт: используйте DayOfWeek::ordinalдля сравнения с числовой константой вместо константы перечисления.
    Спасибо @TimmyD за общую идею, если не точное решение! ;-)
Оливье Грегуар
источник
@TimmyD к сожалению, это перечисление. Однако у него есть getValue()метод, который бы сэкономил несколько байтов.
Celos
@Celos ordinal()экономит на 1 байт больше по сравнению с тем getValue(), что предлагается никогда не использовать.
Оливье Грегуар
да, хорошо подумать Я разместил свой комментарий без предварительного обновления, поэтому я не видел ваш ответ и не редактировал.
Celos
1

GNU awk, 80 байт

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

пример

$ gawk '{for(;m<13;a=mktime($0" "++m" 1 9 0 0")){if(strftime("%w",a-8e4)~1){print m-1}}}' <<<2016
2
10
$
Стив
источник