Five weekends: Difference between revisions
No edit summary |
→{{header|D}}: adding GAP |
||
Line 49: | Line 49: | ||
output match [[#Python|python]] one. |
output match [[#Python|python]] one. |
||
=={{header|GAP}}== |
|||
<lang gap># return a list of two lists : |
|||
# first is the list of months with five weekends between years y1 and y2 (included) |
|||
# second is the list of years without such months, in the same interval |
|||
FiveWeekends := function(y1, y2) |
|||
local L, yL, badL, d, m, y; |
|||
L := [ ]; |
|||
badL := [ ]; |
|||
for y in [y1 .. y2] do |
|||
yL := [ ]; |
|||
for m in [1, 3, 5, 7, 8, 10, 12] do |
|||
if WeekDay([1, m, y]) = "Fri" then |
|||
d := StringDate([1, m, y]); |
|||
Add(yL, d{[4 .. 11]}); |
|||
fi; |
|||
od; |
|||
if Length(yL) = 0 then |
|||
Add(badL, y); |
|||
else |
|||
Append(L, yL); |
|||
fi; |
|||
od; |
|||
return [ L, badL ]; |
|||
end; |
|||
r := FiveWeekends(1900,2100);; |
|||
n := Length(r[1]); |
|||
# 201 |
|||
Length(r[2]); |
|||
# 29 |
|||
r[1]{[1..5]}; |
|||
# [ "Mar-1901", "Aug-1902", "May-1903", "Jan-1904", "Jul-1904" ] |
|||
r[1]{[n-4..n]}; |
|||
# [ "Mar-2097", "Aug-2098", "May-2099", "Jan-2100", "Oct-2100" ]</lang> |
|||
=={{header|J}}== |
=={{header|J}}== |
Revision as of 21:05, 15 November 2010
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
The month of October in 2010 has five Fridays, five Saturdays, and five Sundays.
The task
- Write a program to show all months that have this same characteristic of five full weekends from the year 1900 through 2100 (Gregorian calendar).
- Show the number of months with this property (there should be 201).
- Show at least the first and last five dates, in order.
Algorithm suggestions
- Count the number of Fridays, Saturdays, and Sundays in every month.
- Find all of the 31-day months that begin on Friday.
Extra credit
Count and/or show all of the years which do not have at least one five-weekend month (there should be 29).
D
<lang d>import std.gregorian ; // this module currently work in progress import std.stdio, std.algorithm, std.array, std.range ;
Date[] m5w(Date start = Date(1900,1,1), Date end = Date(2100,12,31) ) {
Date[] res ; for(Date when = Date(start.year, start.month, 1) ; // adjust to 1st day when < end ; when = Date(when.year, 1 + when.month, 1)) { if(when.endOfMonthDay == 31) // Such month must has 3 + 4*7 if(when.dayOfWeek == 5 ) // days and start at friday res ~= when ; // for 5 FULL weekends. } return res ;
}
bool noM5wByYear(int year) {
return (m5w(Date(year,1,1), Date(year,12,31)).length == 0 ) ;
}
void main() {
auto m = m5w() ; // use default input writefln("There are %d months of which the first and last five are:", m.length) ; foreach(d;m[0..5]~m[$-5..$]) writefln("%s", d.toSimpleString[0..$-2]) ;
auto noM5w = filter!(noM5wByYear)(iota(1900,2101)) ; writefln("There are %d years in the range that do not have " "months with five weekends", array(noM5w).length) ;
}</lang>
output match python one.
GAP
<lang gap># return a list of two lists :
- first is the list of months with five weekends between years y1 and y2 (included)
- second is the list of years without such months, in the same interval
FiveWeekends := function(y1, y2)
local L, yL, badL, d, m, y; L := [ ]; badL := [ ]; for y in [y1 .. y2] do yL := [ ]; for m in [1, 3, 5, 7, 8, 10, 12] do if WeekDay([1, m, y]) = "Fri" then d := StringDate([1, m, y]); Add(yL, d{[4 .. 11]}); fi; od; if Length(yL) = 0 then Add(badL, y); else Append(L, yL); fi; od; return [ L, badL ];
end;
r := FiveWeekends(1900,2100);; n := Length(r[1]);
- 201
Length(r[2]);
- 29
r[1]{[1..5]};
- [ "Mar-1901", "Aug-1902", "May-1903", "Jan-1904", "Jul-1904" ]
r[1]{[n-4..n]};
- [ "Mar-2097", "Aug-2098", "May-2099", "Jan-2100", "Oct-2100" ]</lang>
J
<lang j>require 'types/datetime numeric' find5wkdMonths=: verb define
years=. range 2{. y months=. 1 3 5 7 8 10 12 m5w=. (#~ 0 = weekday) >,{years;months;31 NB. 5 full weekends iff 31st is Sunday(0) >'MMM YYYY' fmtDate toDayNo m5w
)</lang> Usage: <lang j> # find5wkdMonths 1900 2100 NB. number of months found 201
(5&{. , '...' , _5&{.) find5wkdMonths 1900 2100 NB. First and last 5 months found
Mar 1901 Aug 1902 May 1903 Jan 1904 Jul 1904 ... Mar 2097 Aug 2098 May 2099 Jan 2100 Oct 2100
# (range -. {:"1@(_ ". find5wkdMonths)) 1900 2100 NB. number of years without 5 weekend months
29</lang>
Java
<lang java>import java.util.Calendar; import java.util.GregorianCalendar;
public class FiveFSS {
private static boolean[] years = new boolean[201]; //dreizig tage habt september... private static int[] month31 = {Calendar.JANUARY, Calendar.MARCH, Calendar.MAY, Calendar.JULY, Calendar.AUGUST, Calendar.OCTOBER, Calendar.DECEMBER};
public static void main(String[] args) { StringBuilder months = new StringBuilder(); int numMonths = 0; for (int year = 1900; year <= 2100; year++) { for (int month : month31) { Calendar date = new GregorianCalendar(year, month, 1); if (date.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY) { years[year - 1900] = true; numMonths++; //months are 0-indexed in Calendar months.append((date.get(Calendar.MONTH) + 1) + "-" + year +"\n"); } } } System.out.println("There are "+numMonths+" months with five weekends from 1900 through 2100:"); System.out.println(months); System.out.println("Years with no five-weekend months:"); for (int year = 1900; year <= 2100; year++) { if(!years[year - 1900]){ System.out.println(year); } } }
}</lang> Output (middle results cut out):
There are 201 months with five weekends from 1900 through 2100: 3-1901 8-1902 5-1903 1-1904 7-1904 12-1905 3-1907 5-1908 1-1909 10-1909 7-1910 ... 12-2090 8-2092 5-2093 1-2094 10-2094 7-2095 3-2097 8-2098 5-2099 1-2100 10-2100 Years with no five-weekend months: 1900 1906 1917 1923 1928 1934 1945 1951 1956 1962 1973 1979 1984 1990 2001 2007 2012 2018 2029 2035 2040 2046 2057 2063 2068 2074 2085 2091 2096
k
<lang k> cal_j:(_jd[19000101]+!(-/_jd 21010101 19000101)) / enumerate the calendar is_we:(cal_j!7) _lin 4 5 6 / identify friday saturdays and sundays m:__dj[cal_j]%100 / label the months mi:&15=+/'is_we[=m] / group by month and sum the weekend days `0:,"There are ",($#mi)," months with five weekends" m5:(?m)[mi] `0:$5#m5 `0:,"..." `0:$-5#m5 y:1900+!201 / enumerate the years in the range y5:?_ m5%100 / label the years of the months yn5:y@&~y _lin y5 / find any years not in the 5 weekend month list `0:,"There are ",($#yn5)," years without any five-weekend months" `0:,1_,/",",/:$yn5</lang> Output:
There are 201 months with five weekends 190103 190208 190305 190401 190407 ... 209703 209808 209905 210001 210010 There are 29 years without any five-weekend months 1900,1906,1917,1923,1928,1934,1945,1951,1956,1962,1973,1979,1984,1990,2001,2007,2012,2018,2029,2035,2040,2046,2057,2063,2068,2074,2085,2091,2096
Perl 6
<lang perl6># A month has 5 weekends iff it has 31 days and starts on Friday.
- Note: [@happy.end X- ^5].reverse is a workaround; Rakudo does not yet allow [*-5..*].
my @years = 1900 .. 2100; my @ym = @years X < 01 03 05 07 08 10 12 >; # Months with 31 days
my @happy = @ym.map({ Date.new: "$^a-$^b-01" }).grep: { .day-of-week == 5 };
say 'Happy month count: ', +@happy; say 'First happy months: '~ @happy[^5]; say 'Last happy months: '~ @happy[@happy.end X- ^5].reverse; say 'Dreary years count: ', @years - @happy».year.uniq; </lang> Output:
Happy month count: 201 First happy months: 1901-03-01 1902-08-01 1903-05-01 1904-01-01 1904-07-01 Last happy months: 2097-03-01 2098-08-01 2099-05-01 2100-01-01 2100-10-01 Dreary years count: 29
PicoLisp
<lang PicoLisp>(setq Lst
(make (for Y (range 1900 2100) (for M (range 1 12) (and (date Y M 31) (= "Friday" (day (date Y M 1))) (link (list (get *Mon M) Y)) ) ) ) ) )
(prinl "There are " (length Lst) " months with five weekends:") (mapc println (head 5 Lst)) (prinl "...") (mapc println (tail 5 Lst)) (prinl) (setq Lst (diff (range 1900 2100) (uniq (mapcar cadr Lst)))) (prinl "There are " (length Lst) " years with no five-weekend months:") (println Lst)</lang> Output:
There are 201 months with five weekends: (Mar 1901) (Aug 1902) (May 1903) (Jan 1904) (Jul 1904) ... (Mar 2097) (Aug 2098) (May 2099) (Jan 2100) (Oct 2100) There are 29 years with no five-weekend months: (1900 1906 1917 1923 1928 1934 1945 1951 1956 1962 1973 1979 1984 1990 2001 2007 2012 2018 2029 2035 2040 2046 2057 2063 2068 2074 2085 2091 2096)
Python
<lang python>from datetime import timedelta, date
DAY = timedelta(days=1) START, STOP = date(1900, 1, 1), date(2101, 1, 1) WEEKEND = {6, 5, 4} # Sunday is day 6 FMT = '%Y %m(%B)'
def fiveweekendspermonth(start=START, stop=STOP):
'Compute months with five weekends between dates' when = start lastmonth = weekenddays = 0 fiveweekends = [] while when < stop: year, mon, _mday, _h, _m, _s, wday, _yday, _isdst = when.timetuple() if mon != lastmonth: if weekenddays >= 15: fiveweekends.append(when - DAY) weekenddays = 0 lastmonth = mon if wday in WEEKEND: weekenddays += 1 when += DAY return fiveweekends
dates = fiveweekendspermonth() indent = ' ' print('There are %s months of which the first and last five are:' % len(dates)) print(indent +('\n'+indent).join(d.strftime(FMT) for d in dates[:5])) print(indent +'...') print(indent +('\n'+indent).join(d.strftime(FMT) for d in dates[-5:]))
print('\nThere are %i years in the range that do not have months with five weekends'
% len(set(range(START.year, STOP.year)) - {d.year for d in dates}))</lang>
Alternate Algorithm
The condition is equivalent to having a thirty-one day month in which the last day of the month is a Sunday. <lang python>LONGMONTHS = (1, 3, 5, 7, 8, 10, 12) # Jan Mar May Jul Aug Oct Dec def fiveweekendspermonth2(start=START, stop=STOP):
return [date(yr, month, 31) for yr in range(START.year, STOP.year) for month in LONGMONTHS if date(yr, month, 31).timetuple()[6] == 6 # Sunday ]
dates2 = fiveweekendspermonth2() assert dates2 == dates</lang>
Sample Output
There are 201 months of which the first and last five are: 1901 03(March) 1902 08(August) 1903 05(May) 1904 01(January) 1904 07(July) ... 2097 03(March) 2098 08(August) 2099 05(May) 2100 01(January) 2100 10(October) There are 29 years in the range that do not have months with five weekends
Ruby
<lang ruby># if the last day of the month falls on a Sunday and the month has 31 days,
- this is the only case where the month has 5 weekends.
start = Date.parse("1900-01-01") stop = Date.parse("2100-12-31") dates = (start..stop).find_all do |day|
day.mday == 31 and day.wday == 0
end
puts "There are #{dates.size} months with 5 weekends from 1900 to 2100:" puts dates[0, 5].map { |d| d.strftime("%b %Y") }.join("\n") puts "..." puts dates[-5, 5].map { |d| d.strftime("%b %Y") }.join("\n")
years_with_5w = dates.map(&:year)
years = (1900...2100).to_a - years_with_5w
puts "There are #{years.size} years without months with 5 weekends:" puts years.join(", ")</lang>
Output
There are 201 months with 5 weekends from 1900 to 2100: Mar 1901 Aug 1902 May 1903 Jan 1904 Jul 1904 ... Mar 2097 Aug 2098 May 2099 Jan 2100 Oct 2100 There are 29 years without months with 5 weekends: 1900, 1906, 1917, 1923, 1928, 1934, 1945, 1951, 1956, 1962, 1973, 1979, 1984, 1990, 2001, 2007, 2012, 2018, 2029, 2035, 2040, 2046, 2057, 2063, 2068, 2074, 2085, 2091, 2096
Tcl
<lang tcl>package require Tcl 8.5
set months {} set years {} for {set year 1900} {$year <= 2100} {incr year} {
set count [llength $months] foreach month {Jan Mar May Jul Aug Oct Dec} {
set date [clock scan "$month/01/$year" -format "%b/%d/%Y" -locale en_US] if {[clock format $date -format %u] == 5} { # Month with 31 days that starts on a Friday => has 5 weekends lappend months "$month $year" }
} if {$count == [llength $months]} {
# No change to number of months; year must've been without lappend years $year
}
} puts "There are [llength $months] months with five weekends" puts [join [list {*}[lrange $months 0 4] ... {*}[lrange $months end-4 end]] \n] puts "There are [llength $years] years without any five-weekend months" puts [join $years ","]</lang> Output:
There are 201 months with five weekends Mar 1901 Aug 1902 May 1903 Jan 1904 Jul 1904 ... Mar 2097 Aug 2098 May 2099 Jan 2100 Oct 2100 There are 29 years without any five-weekend months 1900,1906,1917,1923,1928,1934,1945,1951,1956,1962,1973,1979,1984,1990,2001,2007,2012,2018,2029,2035,2040,2046,2057,2063,2068,2074,2085,2091,2096