最后一个星期一


27

10月31日,星期一,是万圣节。这让我开始思考-我想知道该月的最后一天也是星期一吗?

输入项

  • 任何表示年份的方便格式的正整数,10000 > y > 0
  • 如果需要,可以用零填充输入(例如,0025年份25)。

输出量

  • 该年的月份列表,其中月份的最后一天是星期一。
  • 只要对读者而言,这可以是月份名称(例如January, March, October),短名称(Jan, Mar, Oct)或数字(1, 3, 10),单独的行,列表或定界符等。
  • 输出格式必须一致:
    • 对于所有年份的输入(这意味着,您不能输出某些输入的月份名称,而其他输出的月份编号)
    • 以及每个输出是一致的(意思是,你不能输出1对于January在相同的输出JulJuly
    • 基本上,选择一种格式并坚持下去。

规则

  • 假设输入/输出为公历,甚至到y = 1
  • properly年必须适当地考虑(提醒一下:每年除以4的年份,除非不是除以100的年份,除非也除以400的年份-并非除以leap年,而2000则不是leap年)。
  • 您可以使用任何喜欢的内置工具或其他日期计算工具。
  • 完整的程序或功能都是可以接受的。如果是函数,则可以返回输出而不是打印输出。
  • 禁止出现标准漏洞
  • 这是因此所有常见的高​​尔夫规则都适用,并且最短的代码(以字节为单位)获胜。

例子

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

排行榜



1
相关但不重复或?
ElPedro '16

@ElPedro相关但不重复。第一个不允许任何内置功能,并要求固定的日期/日期组合(13日,星期五),而第二个要求年份的每个月的最后一个星期日,限制在1900年至3015
。– AdmBorkBork

抱歉@TimmD。我对您的评论有误解。
ElPedro '16

1
@ElPedro没问题!我宁愿有一个问题并且清楚一点,而不是没有问题和一些不清楚的地方。
AdmBorkBork,2016年

Answers:


2

带有dfnscal的Dyalog APL,版本15.0:22;16.0版:19 个字节

校准功能附带默认安装,只需输入即可)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
  • yy>>2)之前加上第4年的数目。
  • 减去yy/100|0)之前的第100年。
  • 加上前400年的数目y; 这是的1/4 y/100|0,所以我们用*3/4|0

然后,将结果乘以7为模。如果让0平均值为星期日,1平均值为星期一等,则结果对应于该年12月31日的星期几。因此,对于12月,我们要检查结果是否为1。这给了我们字符串中的最后一个字符。

11月的最后一天是12月的最后一天之前的31天。这意味着对于11月的最后一天为星期一,12月31日必须为(1 + 31) % 7 = 4=星期四。

重复此过程,直到回到三月(a 3)。无论是否有a日,2月的最后一天都是3月的最后一天之前的31天,因此我们也可以计算出这一天(3 + 31) % 7 = 6。棘手的部分是寻找一月份的正确值:

  • 如果是a年,则一月的最后一天是二月的最后一天之前的29天,结果为(6 + 29) % 7 = 0
  • 否则,它是2月最后一天之前的28天,结果为(6 + 28) % 7 = 6

我们可以使用以下代码段计算是否为a年:

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

0如果y不是is年,则给出,否则为正整数。这导致我们

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

计算一月的日期。但是,我们可以通过逆转条件来做得更好:

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

由于伪造的结果始终为0,因此我们可以将其减少为

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

节省一个宝贵的字节。

将所有内容放在一起,我们遍历字符串中的每个字符,检查每个字符是否等于12月31日的星期几。我们保留匹配的索引,最后返回此数组。这就是没有内置功能的leap年计算方法。


噢,我的大脑,你在阿拉中占了leap年吗?
魔术章鱼缸

2
@carusocomputing这就是为什么!(y%4)*y%100|!(y%400)每年被4整除,除了多年没有被100整除,除非也被400整除
mbomb007

希望y+(y>>2)+(z=y/25>>2)+(z>>2)仍然可以节省您一个字节。
尼尔

@Neil谢谢,但是我找到了一个更好的方法:-)
ETHproductions

不错 我使用,在Batch端口上保存了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]

@ETHproductions 节省了2 4 6个字节。通过以相反的顺序输出月份来保存另一个字节。


我认为您可以通过不带翅膀来节省2个字节.keys()y=>[for(_ of(m=0,Array(12)))if(new Date(y+400,++m).getDay()==2)m]
ETHproductions '16

@ETHproductions我可以通过反转顺序来节省更多字节!
尼尔

反向顺序很好。格式化输出不是此挑战的有趣部分。
AdmBorkBork,2016年

现在,从规范中删除它们时,我们对阵列理解有何政策?
市长蒙蒂

您可以通过Array(12)完全跳过来另外保存2个字节: y=>[for(_ of(m=0,1e11+""))if(new Date(y+400,++m).getDay()==2)m]
ETHproductions '16

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:采用了aross的技巧,并注意到我也可以省略的引号"-1"
但是,-1在MySQL中是必需的:我需要一个完整的日期。

修订版4:m BETWEEN 1 AND 12可以按m>0 AND m<13(-6)进行限制,但完全不需要-无效值将被忽略;警告将计算在内,但不会列出。



@JörgHülsermann我不明白你的意思。
泰特斯(Titus)

应该FROM help_topic没有mysql.工作吗?我也尝试不
约尔格Hülsermann

@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

在@ Adám的帮助下保存了15个字节。

使用内置的日历生成代表月份的字符串数组,然后解析每个字符串以确定是否最后一个星期一是该月的最后一天。它输出每个月作为每个月的月份数。也就是说,Jan = 0Feb = 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艺术吗?
破坏的柠檬

@DestructibleWatermelon确切地说,的输出格式calendar是12个盒子的数组,其中每个盒子包含2d个字符数组
英里

我什至不知道如何在J中执行“每个”操作,但是这已经很短了:I.7=;#&.>".&.>,&.>_2{.&.>calendar 2016如果您将所有“未完全解决的情况”组合在一起,那么您应该可以使它变得很短。
阿达姆,2013年

@Adám谢谢,它使用了一种更好的方法,但是它不是J中的动词。不过,我认为它仍然会有所帮助
英里

我的目的只是启发。我知道这不是动词。
阿达姆,2013年

4

Mathematica,62 57字节

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

匿名函数。以数字作为输入,并返回数字的单元素列表作为输出。老实说,我不确定自己是如何工作的。


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 '16

公平点,更新了此内容,并尝试了bash。
史蒂夫

4

Java 7,186182 172字节

感谢kevin保存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;}

不打高尔夫球

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)

1
之后,我写我的回答,我知道一切都计算自己会更短.. :)顺便说一句,你可以打高尔夫球n%4==0n%4<1; n%400==0n%400<1int c=...;int[]b=...,a=...int c=...,b[]=...,a[]=...
凯文·克鲁伊森

1
ba可以在以下int部分中定义:int ... ,b[]=...,a[]=...
OlivierGrégoire16年

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;}保存了几个字节
悬崖根

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+30i+282个更多的字节
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]

我什至不打算尝试使用Python。辛苦了
ElPedro '16

3

MATL,21字节

12:"G@QhO6(YO9XO77=?@

月以数字显示。

在线尝试!验证所有测试用例

说明

这使用日期转换内置函数。对于给定的年份,它将测试最后几个月的哪一天是星期一。

我们没有明确指定月份的最后一天k(可以是28、29、30或31),而是指定了0-th month of month 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。Ideone中的8.23版本不会削减它。


3

Excel,537个字节

因为–您知道– Excel!

在A1中输入年份。返回月份的十六进制列表;1 = 1月,C = 12月。由于每个月都是个位数,因此不需要分隔符。

=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,表示2月和10月。


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,";
  • 输出提供的年份,而不是全部年份(...始终阅读问题)
  • 忽略的通知(感谢Titus)
  • 更改whilefor,因为它现在是一个单一的一年(再次感谢提图斯)

老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的所有年份,也摆脱了我在一台PC上没有意识到的未定义的var警告。是的,它比旧版本更长,但功能更强大。

老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"...它来表示给定月份的最后日期,但是结果与该线程中先前提到的结果不匹配。


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

啊,看错了问题!以为是多年来。.oops:B也感谢其他建议,请继续关注
CT14.IT 16-10-27

3

PHP,92字节

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

一年的第一天后第二个月1个月检查12次。如果是,则该月的最后一天之前的一天是星期一。


您可以使用echo代替打印并保存1
Octopus

1
@Octopus不三元运营商内部
约尔格Hülsermann

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

编译

gcc -std=c99 -o foo foo.c

不打高尔夫球

归功于相关大师。

迈克尔·基思汤姆CraverC语言程序找到周定日期的一天

问与答Collin Biedenkapp :我如何确定一个月的最后一天是什么?

/* 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,2016年

1
如果(x == 1){z part}否则会更好(x == 3 || x == 5 || x == 8 || x == 10)返回30否则返回31
RosLuP

1
怎么样: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:感谢您的return()点,现在已保存100个字节。
史蒂夫

1
可能最终继续减小直到:u(y,m){返回m-1?30 +((2773 >> m)&1):28+(y%4 == 0 && y%100 || y% 400 == 0);}其中y是年份,m是月份
RosLuP '16

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

它使用一个表,该表包含month年的每个月的最后一天的工作日的偏移量,并使用以7为底的32位带符号字进行编码。如果不是a年,则将1的偏移量加1。 (如您所见y&3||y%25<1&&y&15,用于检查无leap天的年份)。然后,我们简单地遍历每个月并检查其最后一天是否是星期一。实际上很简单,没有丑陋的技巧。在这里,它有点松散:

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 '16

确实,我实际上实际上也喜欢输出中的空格,但是我通常编写我的golf C解决方案,以便它们不需要任何空格,因此当我要检查字符数时,我可以从半折线版本中删除所有空格。
Fors

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,day 0(上个月的最后一天)和month 创建日期2..13。格式化日期日数,如果结果是1,打印当前数目。负号-用作定界符。

千年虫再次来袭!

请注意,在此版本中,范围0..100被解释为1970..2069。对于范围来说0..69,这是没有问题的,因为周的模式每400年重复一次(146097天,恰好是20871周),但是对于范围来说70..99,年份中增加了1900,这不是400的倍数。该问题仅适用于10k范围内的30年数字,最简单的方法是将400加到年数字上以防止2位数字解释(+4个字节):

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

调整

  • 通过使用保存的一个字节!~-$i来比较$i1-1二进制否定时0,逻辑否定是true;每隔数是false),所以不需要括号
  • 通过使用last day ofYYYY-m记号创建日期节省了19个字节
  • 使用datestrtotime代替保存了5个字节date_create
  • 通过从负数开始计数,使用负号作为输出定界符(负的负月号不存在)以及YYYY-m日期的一部分中的delim来节省2个字节
  • 使用mktime代替节省了5个字节strtotime。恢复为使用天0mktime也支持第13个月,所以0-13== 31-12
  • 通过使用节省3个字节-R,使$argn可用

mktime消除了支付年度的必要,不是吗?
泰特斯(Titus)

@泰特斯,尖锐。好吧,我刚刚发现这mktime违反直觉的,因为参数被视为INTs。这意味着您无法填写年份...因此范围内的所有内容都0..100被解释为1970..2070。对于该范围而言,这没有问题,0..70因为400年具有确切的星期数(因此日历每400年重复一次该模式),但是70..99增加了1900年(不是400的倍数!)。因此,新版本。有一个错误。
2016年

我现在看到的唯一解决方案是$argv[1]+400...除非朱利安(Julian)和格里高利(Gregorian)的工作日有所不同。
泰特斯

@Titus,是的。规则说使用格里高利cal
aross 16-10-28

3

Excel,428 97 96字节

输入A1。输出未分隔的十六进制值(一月= 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年之前的日期。

由于@ Engineer Toast节省了11个字节。


第一次尝试(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","")

在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
Digital Trauma

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]

代表

一个未命名的函数,使用整数年,输出月数列表[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)

一个未命名的函数,该函数返回一个布尔值列表,该布尔值列表表示[Jan-Dec]月是否在星期一结束


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));仅通过强制使用公历来解决此问题。感谢stackoverflow.com 上的@JonSkeet向我解释这一点。

取消测试代码:

在这里尝试。

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字节感谢Shebang

将月份打印为数字;用空格分隔;与尾随的空间。现在,此答案也适用于早期版本的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

输出月份是返回字符串中的数字,以逗号分隔

不打高尔夫球

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是的,但需要显式强制转换。解答已更新
链接吴

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);}}};)此外,这将是短铸DayOfWeekint比这将是投了intDayOfWeek
卡德

@Shebang谢谢。我真的不应该单打高尔夫球,只有Jon Skeet可以做到。看看我明天是否有时间更新。现在累了。
Link Ng

您可以将其转换为a Action<int>以节省一些字节
TheLethalCoder

2

Ruby,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]

-rdate命令行上有6个字节,用于从标准库中获取Date类。

说明:非常感谢Ruby stdlib的出色Date类。它不仅具有类似的方法monday?tuesday?等等,构造将采取负数的任何领域过去的一年里指“从期末由前场表现算这个领域倒退”。$*是的简写ARGV,因此$*[0]是获取第一个命令行参数的快速方法。


2

PHP,84字节

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

我的第一个Code Golf。这是迄今为止在这个问题上最短的PHP。

编辑:似乎不适用于第一年。我必须弄清楚为什么,但是现在我必须走了。


1
我会说“欢迎使用PPCG!” 但是您在这里的注册时间比我更长!:D不错的第一场高尔夫球。
AdmBorkBork '16

您的错误是您为1 <13年创建1-13-1和1-14-1就足够了。如果你解决这个问题,你可以删除unnessary括号中的那一刻,想想使用三元运算符
约尔格Hülsermann

这应该固定您的问题for(;$m++<12;)strftime("%w",strtotime($argv[1]+($m/12^0)."-".($m%12+1)."-1"))!=2?:print"$m ";
约尔格Hülsermann

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",然后由转换为2016年2月1日as.Date

  • seq施加到POSIXct或Date对象是seq(from, to , by, length.out):这里to没有给出,by被给定为'm',其匹配于'month'由于部分匹配,并且length.out当然是12。

  • 结果序列是从相关年份的2月开始的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]

这个答案真是太好了。我不知道seq有一种用于Date-objects 的方法,这解决了在我删除的答案中as.Date不处理以上年份的10000问题。
Billywob

@Billywob是的seq.Dateseq.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

1

Java,143129字节

这使用了Java 8的新时间API。

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's

与@Celos ordinal()相比getValue(),它节省了1个字节,即使建议不要使用它。
奥利维尔·格雷戈尔(OlivierGrégoire),2013年

是的,好主意。我发表评论时没有先刷新,所以看不到您的回复和编辑。
Celos '16

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
$
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.