一个月中工作日的百分比


11

给定一年零一个月,找出该月工作日的百分比。工作日为星期一至星期五,与节假日或其他特殊情况无关。使用公历。

输入值

ISO 8601格式的年月(YYYY-MM)。年份始终具有四个数字,月份始终具有两个数字。给定的年份不会早于1582年。

输出量

输出是给定月份的工作日百分比(根据上述定义),四舍五入为整数。没有百分号或小数位。

样品1

Input                Output

2010-05              68

样品2

Input                Output

2010-06              73

样品3

Input                Output

1920-10              68

样品4

Input                Output

2817-12              68

一个星期过去了,答案已经被接受。出于好奇,我们在比赛中收到的意见书的大小:

129 – Z Shell
174 – VB.NET
222 – C
233 – C
300 – C

以及我们自己的(未排名)解决方案:

  75 – PowerShell
  93 – Ruby
112 – Bourne shell


2
我是研究生,所以……echo 100
Amory

即使是研究生,也无法逃脱工作中的基本定义。而且我对工作日的定义也不同;-)
Joey

Answers:


4

64位Perl,67 68

Perl 5.10或更高版本,使用perl -E 'code here'perl -M5.010 filename

map{$d++,/^S/||$w++if$_=`date -d@ARGV-$_`}1..31;say int.5+100*$w/$d

优惠码大小:

  • 区域敏感:将date不以大写字母S开头的日期视为工作日LC_ALL=C
  • 输出是纯格式且格式正确,但2> /dev/null如果不正常,则在短于31的月份,stderr上会出现“垃圾” 。
  • 由于某种原因,我的版本date认为2817-12无效月份。谁知道,GNU新的启示就要到了!需要date2038年之后的日期的64位版本。(感谢Joey)

1
显然,“ Siphous Hemes”在他统治期间废除了它。ref “圣经的新历史”
马丁·约克

1
2038年以后的每一年都破了吗?然后切换ta 64位版本可能会由于日期处理方面的某些脑力衰竭而有所帮助;-)
Joey

@Joey就是这样。谢谢你的提示!
JB

JB:只是一个猜测,实际上我没想到C之外的任何东西仍然只使用32位整数,该整数自怪异的时代起算秒。不过,老实说,我正是出于这个目的而将日期> 2038的要求放在那里;-)
Joey

3

PHP-135

我之所以使用PHP,是因为几天前我遇到了类似的问题

<?php $a=array(2,3,3,3,2,1,1);$t=strtotime($argv[1]);$m=date(t,$t);echo round((20+min($m-28,$a[date(w,strtotime('28day',$t))]))/$m*100)

(有点)更清晰,并且没有将常量用作字符串的通知:

<?php
date_default_timezone_set('America/New_York');
$additionalDays = array(2, 3, 3, 3, 2, 1, 1);
$timestamp = strtotime($argv[1]);
$daysInMonth = date('t', $timestamp);
$limit = $daysInMonth - 28;
$twentyNinthDayIndex = date('w', strtotime("+28 days", $timestamp));
$add = $additionalDays[$twentyNinthDayIndex];
$numberOfWorkDays = 20 + min($limit, $add);
echo round($numberOfWorkDays / $daysInMonth * 100);
?>

这可以通过一种非常简单的算法来计算一个月的工作日数来实现:检查29日,30日和31日的工作日(如果存在这些日期),然后加20。


好的算法,不好的打高尔夫球。使用当代的PHP 5.3.5和-R,可以将该方法压缩为86个字节(63.7%):$a="2333211";echo.5+min(-8+$m=date(t,$t=strtotime($argn)),20+$a[date(w,$t)])/$m*100|0; 请参见打高尔夫球的步骤。
泰特斯

80个字节:<?=.5+min(-8+$m=date(t,$t=strtotime($argn)),20+(5886>>date(w,$t)*2&3))/$m*100|0;
Titus

2

Python 152个字符

from calendar import*
y,m=map(int,raw_input().split('-'))
c=r=monthrange(y,m)[1]
for d in range(1,r+1):
 if weekday(y,m,d)>4:c-=1
print '%.f'%(c*100./r)

2

Bash + coreutils,82个字节

f()(cal -NMd$1|sed -n "s/^$2.//p"|wc -w)
dc -e`f $1 "[^S ]"`d`f $1 S`+r200*r/1+2/p

2

Windows PowerShell,80

$x=$args;1..31|%{"$x-$_"|date -u %u -ea 0}|%{$a++
$b+=!!($_%6)}
[int]($b*100/$a)

你确定[int]真的是回合吗?我倾向于相信它。
zneak 2011年

@zneak:PowerShell不是C或C衍生的语言。它使用.NET的默认舍入模式,即“舍入到最接近的偶数”。只需尝试一下:两者[int]1.5[int]2.5yield 2。这种精确的行为通常会在需要进行底数除法的任务中引起问题(然后需要额外的除法[Math]::Floor()),但是在这种情况下,它不会受到损害,并且“四舍五入”仅适用于在.5此不可能发生的数字。
乔伊,

如果您确定,那我相信您。我只是希望它能像C#一样工作,而且我没有任何Windows机器可以在家进行测试。
zneak 2011年

@zneak:不,绝对不能像C#那样工作。[int]在PowerShell中类似的东西通常更多是转换,而不是强制转换:-)。诸如此类的事情[int[]][char[]]'abc'也可以用其他许多语言来工作。
乔伊,

Necrobump但$input-> $args保存一个字节。
维斯卡

1

D:186个字符

auto f(S)(S s){auto d=Date.fromISOExtendedString(s~"-28"),e=d.endOfMonth;int n=20;while(1){d+=dur!"days"(1);if(d>e)break;int w=d.dayOfWeek;if(w>0&&w<6)++n;}return rndtol(n*100.0/e.day);}

更清晰:

auto f(S)(S s)
{
    auto d = Date.fromISOExtendedString(s ~ "-28"), e = d.endOfMonth;
    int n = 20;

    while(1)
    {
        d += dur!"days"(1);

        if(d > e)
            break;

        int w = d.dayOfWeek;

        if(w > 0 && w < 6)
            ++n;
    }

    return rndtol(n * 100.0 / e.day);
}

1

蟒蛇-142

from calendar import*
y,m=map(int,raw_input().split('-'))
f,r=monthrange(y,m)
print'%.f'%((r-sum(weekday(y,m,d+1)>4for d in range(r)))*100./r)

感谢fR0DDY的日历位。


1

红宝石,124 119 111

require 'date'
e=Date.civil *$*[0].split(?-).map(&:to_i),-1
p ((e+1<<1..e).count{|d|d.cwday<6}*1e2/e.day).round

需要Ruby 1.9,因为将-1和“ day”参数的年份和月份分别放在和?-"-"。对于Ruby 1.8,我们必须添加2个字符:

require 'date'
e=Date.civil *$*[0].split('-').map(&:to_i)<<-1
p ((e+1<<1..e).count{|d|d.cwday<6}*1e2/e.day).round

编辑:基于@Dogbert的帮助剃除五个字符。
编辑:在@steenslag的帮助下,还可刮掉八个字符。


为什么要将日期分配给D?
Dogbert

@Dogbert糟糕!从我拥有两个Date.civils的时间开始;谢谢!
Phrogz

'-'可以用?-Ruby 1.9 编写
Dogbert

@Dogbert尼斯。我也会把它扔进去。我觉得选择工作日的方法肯定比较短,但我还没有找到。
Phrogz

e + 1 << 1比ee.day + 1短三倍
steenslag 2011年

1

PHP 5.2,88字节

尽管我已经将zneak的解决方案压缩到了85个字节(我刚刚发现了一个字节),但这是我自己的解决方案
我怀疑我是否可以在这里再压缩三个字节。

$a=_4444444255555236666304777411;echo$a[date(t,$t=strtotime($argn))%28*7+date(N,$t)]+67;

接受来自STDIN的输入:使用运行echo <yyyy>-<mm> | php -nR '<code>'

该字符串$a将每月的天数(date(t))和该月第一天的工作日(date(N):Monday = 1,Sunday = 7)映射到工作日的百分比-67;strtotime将输入转换为UNIX时间戳;其余代码进行哈希处理。

+1字节为老年人PHP 5:更换Nw$a=_...;$a="..."
PHP 4的另一个+3字节:在.-1之后插入$argn

-5.5字节(适用于PHP 5.5或更高版本)(挑战发布日期较早):
删除所有内容echo并替换$a"4444444255555236666304777411"


嗯...一个字节:%7代替%28
泰特斯

0

REBOL - 118 113

w: b: 0 o: d: do join input"-01"while[d/2 = o/2][if d/7 < 6[++ w]++ b d: o + b]print to-integer round w / b * 100

取消高尔夫:

w: b: 0 
o: d: do join input "-01"
while [d/2 = o/2] [
    if d/7 < 6 [++ w]
    ++ b
    d: o + b
]
print to-integer round w / b * 100

0

C#,158个字节

s=>{var d=DateTime.Parse(s);int i=0,t=DateTime.DaysInMonth(d.Year,d.Month),w=0;while(i<t)w-=-(int)d.AddDays(i++).DayOfWeek%6>>31;return Math.Round(1e2*w/t);};

返回所需百分比的匿名方法。

完整的程序,包含未注释的方法和测试用例:

using System;

class WorkingDayPercentage
{
    static void Main()
    {
        Func <string, double> f =
        s =>
        {
            var d = DateTime.Parse(s);                      // extracts a DateTime object from the supplied string
            int i = 0,                                      // index variable
                t = DateTime.DaysInMonth(d.Year, d.Month),  // number of total number of days in the specified month
                w = 0;                                      // number of working days in the month

            while (i < t)                                   // iterates through the days of the month
                w -= -(int)d.AddDays(i++).DayOfWeek%6 >> 31;// d.AddDays(i) is the current day
                                                            // i++ increments the index variable to go to the next day
                                                            // .DayOfWeek is an enum which hold the weekdays
                                                            // (int)..DayOfWeek gets the days's index in the enum
                                                            // note that 6 is Saturday, 0 is Sunday, 1 is Monday etc.
                                                            // (int)DayOfWeek % 6 converts weekend days to 0
                                                            // while working days stay strictly positive
                                                            // - changes the sign of the positive numbers
                                                            // >> 31 extracts the signum
                                                            // which is -1 for negative numbers (working days)
                                                            // weekend days remain 0
                                                            // w -= substracts the negative numbers
                                                            // equivalent to adding their modulus

            return Math.Round(1e2 * w / t);                 // the Math.round function requires a double or a decimal
                                                            // working days and total number of days are integers
                                                            // also, a percentage must be returned
                                                            // multiplying with 100.0 converts the expression to a double
                                                            // however, 1e2 is used to shorten the code
        };

        // test cases:
        Console.WriteLine(f("2010-05")); // 68
        Console.WriteLine(f("2010-06")); // 73
        Console.WriteLine(f("1920-10")); // 68
        Console.WriteLine(f("2817-12")); // 68
    }
}

替代功能,它将负值添加到工作天数中,无需额外的字节费用即可更改返回中的符号:

s=>{var d=DateTime.Parse(s);int i=0,t=DateTime.DaysInMonth(d.Year,d.Month),w=0;while(i<t)w+=-(int)d.AddDays(i++).DayOfWeek%6>>31;return-Math.Round(1e2*w/t);};

0

Oracle SQL,110字节

select round(100*sum(1-trunc(to_char(x+level-1,'d')/6))/sum(1))from dual,t connect by level<=add_months(x,1)-x

它假设输入数据使用date数据类型存储在表中,例如

with t as (select to_date('2010-06','yyyy-mm') x from dual)

0

APL(Dyalog Unicode),55 字节SBCS

匿名默认前缀功能。

.5+100×2÷/(2 5)2{≢⍎⍕↓⍺↓¯2' ',cal' '@5⊢⍵⊣⎕CY'dfns'}¨⊂

 附上日期以将其视为一个整体

(2 5)2{ 在其上应用以下函数,但使用左参数[2,5]2

⎕CY'dfns' 复制“ dfns”库

⍵⊣ 放弃该报告以代替日期

' '@5⊢ 用-空格替换第5个字符()

 执行该操作以获取两个元素的列表

cal 调用日历功能

' ', 在那之前加一列空格

¯2⌽ 将最后两列(星期六)旋转到前面

⍺↓ 删除左参数行(2,标题)和列的数目(如果指定; 5 = Sat + Sun)

 将矩阵拆分为行列表

 格式(插入双倍空格时变平)

 执行(将剩余的日期数字转换为平面数字列表)

 记录那些

2÷/ 将每一对分开(只有一对)

100× 乘以一百

.5+ 加一半

 地板

在线尝试!


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.