14
$\begingroup$

I'd like to find a fast but readable way to achieve the following:

Cases[RandomInteger[{AbsoluteTime["2001"], AbsoluteTime["2003"]}, 1000], 
a_ /; a > AbsoluteTime["2002"]]

The correct result can be achieved much faster using with:

With[{d = AbsoluteTime["2002"]},
Cases[RandomInteger[{AbsoluteTime["2001"], AbsoluteTime["2003"]}, 1000],
a_ /; a > d]]

But this is not very readable. Is there a more readable way?

$\endgroup$
12
$\begingroup$

You could inject the value once with a Function instead of With.

Cases[RandomInteger[{AbsoluteTime["2001"], AbsoluteTime["2003"]}, 
    1000], a_ /; a > #] &@ AbsoluteTime["2002"]

In V10, we can use named arguments, which is arguably [sic] more readable (and more typing):

Cases[RandomInteger[{AbsoluteTime["2001"], AbsoluteTime["2003"]}, 
    1000], a_ /; a > #time] &[<|"time" -> AbsoluteTime["2002"]|>]

One could use Evaluate, although this would fail if a has a global value.

Cases[RandomInteger[{AbsoluteTime["2001"], AbsoluteTime["2003"]}, 
  1000], a_ /; Evaluate[a > AbsoluteTime["2002"]]]

Protecting a with Block is a possibility, albeit a little cumbersome.

Block[{a},
 Cases[RandomInteger[{AbsoluteTime["2001"], AbsoluteTime["2003"]}, 
   1000], a_ /; Evaluate[a > AbsoluteTime["2002"]]]
 ]
$\endgroup$
10
$\begingroup$

I rather like the With construction and feel it's quite readable, but if you don't want to use it, how about:

Cases[
  RandomInteger[{AbsoluteTime["2001"], AbsoluteTime["2003"]}, 1000]
  - AbsoluteTime["2002"], 
  a_ /; a > 0
] +  AbsoluteTime["2002"] 

or

Cases[
  RandomInteger[{AbsoluteTime["2001"], AbsoluteTime["2003"]}, 1000]
  - AbsoluteTime["2002"], 
  _?Positive
] +  AbsoluteTime["2002"] 

or, with Select

Select[
  RandomInteger[{AbsoluteTime["2001"], AbsoluteTime["2003"]}, 1000] 
  - AbsoluteTime["2002"], 
  Positive
] + AbsoluteTime["2002"]

which are all 200 times faster than your original and about as fast as With (though not particularly readable either).

$\endgroup$
10
$\begingroup$

For a different approach, how about a memoized version of AbsoluteTime:

at[x_] := at[x] = AbsoluteTime[x]

Cases[RandomInteger[{at["2001"], at["2003"]}, 1000], a_ /; a > at["2002"]]
$\endgroup$
  • $\begingroup$ I like this (+1); it is about twice as fast as the original. I wonder whether this meets the OP's readability requirement, though. This is similar to starting with a With definition except that here the definition goes in global namespace. Just defining the value as a variable (together with your at in the random generator) is about two times faster still: d = AbsoluteTime["2002"]; Cases[RandomInteger[{at["2001"], at["2003"]}, 1000], a_ /; a > d]. $\endgroup$ – Sjoerd C. de Vries Oct 13 '15 at 21:59
6
$\begingroup$

With is designed to address the issue you bring up. The way to make your code readable is pick better variable names.

With[{midPoint = AbsoluteTime["2002"]}, 
  Cases[RandomInteger[{AbsoluteTime["2001"], AbsoluteTime["2003"]}, 1000], 
    time_ /; time > midPoint]]
$\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.