3
$\begingroup$

I am trying to generate a list of dates that match two criteria: they have to all be the first of the month, and they have to be a particular day of the week, Sunday in my case.

The code I have written is this:

Select[DayRange[{1901, 1, 1}, {2000, 12, 31}], DayName[#] == Sunday && # == {_, _, 1} &]

I.e. I want to Select only those days in between the DayRange 1 january 1901 and 31 December 2000 that match the criteria of being a Sunday as well as (&&) being the first of the month ({_, _, 1}).

However, this function just outputs an empty list.

I'm still new to Mathematica, but in as far as I can see everything here should work fine. What am I doing wrong?

$\endgroup$
  • 1
    $\begingroup$ # == {_, _, 1} should use MatchQ instead of ==. $\endgroup$ – Szabolcs Mar 4 '14 at 0:57
  • $\begingroup$ Ah thank you! Is that because the # == {_, _, 1} form cannot interpret patterns? $\endgroup$ – Aron Mar 4 '14 at 1:04
  • $\begingroup$ Think of patterns like regexes. Your expression isn't "equal" to a regex. Your expression "matches" it. $\endgroup$ – Dr. belisarius Mar 4 '14 at 1:08
  • $\begingroup$ Yes. == is for numbers and equations (i.e. math), === is for testing if expressions are structurally identical (i.e. programming only, no math), MatchQ is for pattern matching. $\endgroup$ – Szabolcs Mar 4 '14 at 1:10
  • $\begingroup$ Got it. Thanks @belisarius! And @Szabolcs, you've been extremely helpful to me the past few days! $\endgroup$ – Aron Mar 4 '14 at 1:10
6
$\begingroup$
Select[Cases[DayRange[{1901, 1, 1}, {2000, 12, 31}], {_, _, 1}], DayName[#] == Sunday &]

or more concisely:

Cases[DayRange[{1901, 1, 1}, {2000, 12, 31}], d : {_, _, 1} /; DayName[d] == Sunday]

Does it. If you want to keep it all in a select,

Select[DayRange[{1901, 1, 1}, {2000, 12, 31}], (DayName[#] == Sunday && MatchQ[#, {_, _, 1}]) &]

Does the same, but slower.

By far the faster:

Cases[DayRange[{1901, 1, 1}, {2000, 12, 31}, Sunday], {_, _, 1}]

Edit: Per comment below, with changes in later versions of Mathematica, the last example becomes:

Cases[DayRange[{1900, 1, 1}, {2000, 12, 31}, Sunday], d_ /; DateValue[d, "Day"] == 1]

I will revisit when time permits to include modified versions of other examples and compare performance, along with experimenting with new date function characteristics to determine if a yet more efficient implementation exists.

$\endgroup$
  • $\begingroup$ Thank you @rasher! This was my first foray into pattern matching - I'm still not clear exactly how patterns and forms work, but your answer (especially the second form) gave me a better understanding $\endgroup$ – Aron Mar 4 '14 at 1:15
  • $\begingroup$ @anon: Take a look also at the docs for DayRange: using the construct of the last in my answer is over 100X faster, since it lets the low-level code of DayRange filter out the "Sunday" requirement... $\endgroup$ – ciao Mar 4 '14 at 1:17
  • $\begingroup$ @rasher just edited typographical error (-> concisely): am learning from and enjoying your answers $\endgroup$ – ubpdqn Mar 4 '14 at 9:38
  • $\begingroup$ @ubpdqn: Thanks for edit & kind words - not so sure there's anything to learn from me other than I'm a pour speller ;-} $\endgroup$ – ciao Mar 4 '14 at 9:43
  • $\begingroup$ @rasher always learning...MSE good diversion from 'real world' at present :) $\endgroup$ – ubpdqn Mar 4 '14 at 9:47
2
$\begingroup$

I have voted for rasher's excellent answer but just to illustrate Pick:

With[{dr = DayRange[{1901, 1, 1}, {2000, 12, 31},Sunday]},
 Pick[dr, Last@# == 1 & /@ dr]]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.