Bir aydaki iş günü yüzdesi


11

Bir yıl ve bir ay göz önüne alındığında, söz konusu aydaki iş günü yüzdesini öğrenin. İş günleri, tatil günleri veya diğer özel şeyler dikkate alınmaksızın Pazartesi'den Cuma'ya kadardır. Gregoryen takvimi kullanılır.

Giriş

ISO 8601 formatında bir yıl ve ay (YYYY-AA). Yıl her zaman dört basamaklıdır, ay her zaman iki basamaklıdır. Söz konusu yıl 1582'den önce olmayacak.

Çıktı

Çıktı, belirli bir aydaki bir tam sayıya yuvarlanan iş günü yüzdesidir (yukarıdaki tanıma göre). Bunu yüzde işareti veya kesirli basamak izlemez.

Numune 1

Input                Output

2010-05              68

Numune 2

Input                Output

2010-06              73

Numune 3

Input                Output

1920-10              68

Numune 4

Input                Output

2817-12              68

Bir hafta geçti, bir cevap kabul edildi. Meraklı için yarışmamızda sunduğumuz sunumların boyutları:

129 - Z kabuğu
174 - VB.NET
222 - C
233 - C
300 - C

Kendi çözümümüzün yanı sıra:

  75 - PowerShell
  93 - Yakut
112 - Bourne kabuğu


2
Ben bir yüksek lisans öğrencisiyim, yani ...echo 100
Amory

Mezun öğrenciler bile çalışma alanlarındaki temel tanımlardan kaçamazlar. Ve iş günlerini farklı tanımladım ;-)
Joey

Yanıtlar:


4

64-bit Perl, 67 68

Perl 5.10 veya üstü, perl -E 'code here'veya ile çalıştırınperl -M5.010 filename

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

Kod boyutuna ilişkin tavizler:

  • yerel ayarlara duyarlı: dateçıktıları büyük S ile başlamayan günler iş günü olarak sayılır LC_ALL=C.
  • çıktı saf ve iyi biçimlendirilmiş, ancak stderr üzerinde 31'den kısa aylarda "çöp" var 2> /dev/null.
  • bazı nedenlerden dolayı benim versiyonum date2817-12'yi geçersiz bir ay olarak görüyor. Kim bilir, GNU yeni kıyamet zamanı geldi! date2038'den sonraki tarihler için 64 bitlik bir yapı gerektirir. (Teşekkürler Joey)

1
Görünüşe göre yönetimi sırasında "Siphous Hemes" tarafından kaldırıldı. ref "İncil'de yeni bir tarih"
Martin York

1
2038'den sonraki her yıl kırıldı mı? Sonra ta 64-bit derleme geçiş tarih işleme ;-) ile bazı braindead-ness nedeniyle yardımcı olabilir
Joey

@Joey tam olarak bu. Bahşiş için teşekkürler!
JB

JB: Sadece bir tahmindi ve aslında C'nin ötesinde hiçbir şeyin tuhaf bir çağdan beri saniyeler içinde sadece 32 bitlik tamsayılar kullanmasını beklemiyordum. Dürüst olmak gerekirse, tam olarak bu amaç için 2038'den büyük tarihler koydum ;-)
Joey

3

PHP - 135

Birkaç gün önce tedavi etmek için benzer bir sorun vardı çünkü PHP'de yaptı .

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

(Biraz) Daha okunaklı ve sabit olarak dize olarak kullanıldığına dair bildirimde bulunulmadan:

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

Bu, bir aydaki iş günü sayısını hesaplamak için çok basit bir algoritma ile mümkün olur: 29, 30 ve 31'in haftada birliğini kontrol edin (bu tarihler varsa) ve 20 ekleyin.


Harika algoritma, zayıf golf. Çağdaş PHP 5.3.5 ve kullanarak -R, bu yaklaşım 86 bayta kadar azaltılabilir (% 63.7): $a="2333211";echo.5+min(-8+$m=date(t,$t=strtotime($argn)),20+$a[date(w,$t)])/$m*100|0; Golf adımlarına bakın.
Titus

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

2

Python 152 Karakterleri

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 bayt

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]Gerçekten mermi olduğundan emin misin ? Kat olduğuna inanma eğilimindeydim.
zneak

@zneak: PowerShell C veya C'den türetilmiş bir dil değildir. .NET'in varsayılan yuvarlama modunu kullanır. Sadece denemek: Her iki [int]1.5ve [int]2.5verim 2. Bu kesin davranış genellikle, katlanmış bölünmenin gerekli olduğu görevlerde sorunlara neden olur (bu daha sonra bir ekstra gerektirir [Math]::Floor()), ancak bu durumda incinmez ve »hatta yuvarla« yalnızca .5burada bitmeyen sayılara uygulanır .
Joey

Eğer eminseniz, o zaman size inanıyorum. Bunun yerine C # gibi çalışmasını bekliyordum ve evde test edeceğim herhangi bir Windows makinem yok.
zneak

@zneak: Hayır, kesinlikle C #'daki gibi çalışmıyor. [int]PowerShell'de olduğu gibi bir şey genellikle bir oyuncudan daha fazla dönüşümdür :-). [int[]][char[]]'abc'Diğer birçok dilde çalışamayacağınız şeyler de işe yarıyor.
Joey

Necrobump ama $input-> $argsbir bayt kaydeder.
Veskah

1

D: 186 Karakter

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

Daha okunaklı:

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

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

Takvim biti için fR0DDY'ye teşekkürler.


1

Yakut, 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

Nedeniyle -1 "gün" argüman önce ve yıl ve ay splatting Ruby 1.9 gerektirir ?-için "-". Ruby 1.8 için 2 karakter eklemeliyiz:

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

Düzenleme : @ Dogbert'in yardımına dayanarak beş karakter tıraş edin.
Düzenleme : @ steenslag'ın yardımına dayanarak sekiz karakter daha tıraş edin.


Neden D'ye Tarih atarsınız?
Dogbert

@Dogbert Whoops! Ben iki Date.civils vardı bir zamandan itibaren Holdover; Teşekkürler!
Phrogz

'-'?-Ruby 1.9'da olduğu gibi yazılabilir
Dogbert

@Dobert Nice. Bunu ben de atacağım. Hafta günlerini seçmenin daha kısa bir yolu olması gerektiğini hissediyorum, ama henüz bulamadım.
Phrogz

e + 1 << 1 ee.day + 1'den üç daha kısadır
steenslag

1

PHP 5.2, 88 bayt

Zneak´ın çözümünü 85 bayta kadar indirmiş olmama rağmen (sadece bir tane daha buldum), burada kendi: Burada üç bayt daha sıkabileceğimden şüpheliyim
.

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

STDIN'den girdi alır: ile çalıştır echo <yyyy>-<mm> | php -nR '<code>'.

Dize $aaydaki günleri ( date(t)) ve ayın ilk gününün hafta gününü ( date(N): Pazartesi = 1, Pazar = 7) iş günü-67; strtotimegirişi bir UNIX zaman damgasına dönüştürür; kodun geri kalanı karma yapar.

Eski PHP 5 için 1 bayt: Değiştir Nile wve $a=_...;ile $a="...".
PHP 4 için başka bir +3 bayt: .-1sonra ekleyin $argn.

-5 PHP 5.5 için bayt veya sonrası (meydan postdates):
Kaldır her şey önce echove değiştirme $aile "4444444255555236666304777411".


Şey ... bir bayt: %7yerine %28.
Titus

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

Ungolfed:

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 bayt

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

Gerekli yüzdeyi döndüren anonim yöntem.

Yassız, yorumlanmış yöntem ve test senaryoları ile tam program:

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

İş günü sayısına negatif değerler ekleyen ve ekstra bayt maliyeti olmadan dönüşteki işareti değiştiren alternatif işlev:

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 bayt

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

Giriş verilerinin dateveri türü kullanılarak bir tabloda depolandığı varsayımıyla çalışır , ör.

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

0

APL (Dyalog Unicode) , 55 bayt SBCS

Anonim zımni önek fonksiyonu.

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

 bir bütün olarak ele almak için tarihi ekleyin

(2 5)2{...  ama sol argümanlarla, bu konuda aşağıdaki işlevi uygulamak [2,5]ve 2:

⎕CY'dfns' "dfns" kütüphanesini kopyala

⍵⊣ raporu tarih lehine at

' '@5⊢ 5. karakteri ( -) boşlukla değiştir

 iki elemanlı liste almak için bunu yürütün

cal Takvim işlevini çağırın

' ', buna bir boşluk sütunu ekle

¯2⌽ son iki sütunu (Cumartesi) öne döndür

⍺↓ satırdan sola bağımsız değişken sayısını (2, üstbilgi) ve sütunları (belirtilmişse; 5 = Cts + Paz)

 matrisi satır listesine bölme

 biçimi (çift aralık ekleyerek düzleşir)

 yürütme (kalan gün sayılarını düz sayısal listeye dönüştürür)

 bunları hesapla

2÷/ her çifti böl (sadece bir tane var)

100× yüz ile çarp

.5+ yarım ekle

 zemin

Çevrimiçi deneyin!


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.