5
$\begingroup$

The symbol UpTo emerged as a sort of "safe take" in version 10:

Take[{1, 2, 3}, UpTo[4]]
(* Out: {1, 2, 3} *)

But it wasn't designed to handle negative indices or spans:

Take[{1, 2, 3}, UpTo[-4]]
(* Out: Take[{1, 2, 3}, UpTo[-4]] *)

Here's what I would expect the output to be:

Take[{1, 2, 3}, UpTo[-1]] (*  3        *)
Take[{1, 2, 3}, UpTo[-2]] (* {2, 3}    *)
Take[{1, 2, 3}, UpTo[-4]] (* {1, 2, 3} *)

Instead we get these errors:

During evaluation of In[2]:= UpTo::innf: Non-negative integer or Infinity expected at position 1 in UpTo[-4]. >>

During evaluation of In[2]:= Take::seqs: Sequence specification (+n, -n, {+n}, {-n}, {m, n}, or {m, n, s}) expected at position 2 in Take[{1,2,3},UpTo[-4]]. >>

It seems that UpTo is an inert wrapper. Is there anyway to overload Take to get this functionality?

$\endgroup$
  • $\begingroup$ Having Take[{1, 2, 3}, UpTo[-4]] not being evaluated is inconsistent with the behaviour of UpTo. This should return {1, 2, 3} as UpTo[4] would return. Correct? $\endgroup$ – Edmund Apr 18 '16 at 1:49
  • $\begingroup$ Yes that's better $\endgroup$ – M.R. Apr 18 '16 at 1:51
6
$\begingroup$

Update to use UpTo

By Unprotecting UpTo and adding an UpValue for Negative values.

Unprotect[UpTo];
UpTo /:
  Take[list_List, UpTo[n_Integer?Negative]] := list[[Max[-Length@list, n] ;;]];
Protect[UpTo];

Can also turn off the non-negative error message.

Off[UpTo::innf];

Then

Take[{1, 2, 3}, UpTo[-1]]
(* {3} *)

Take[{1, 2, 3}, UpTo[-10]]
(* {1, 2, 3} *)

Original Post

With UpValues on a new symbol downTo.

downTo /:
 Take[list_List, downTo[n_Integer?Negative]] := list[[Max[-Length@list, n] ;;]]

Then

Take[{1, 2, 3}, downTo[-1]]
(* {3} *)

Take[{1, 2, 3}, downTo[-3]]
(* {1, 2, 3} *)

Take[{1, 2, 3}, downTo[-10]]
(* {1, 2, 3} *)

Hope this helps.

| improve this answer | |
$\endgroup$
  • $\begingroup$ I did try this option already and it works nicely, but I'm hoping there is someway to overload UpTo, the reason being so that I don't have to special case my code. $\endgroup$ – M.R. Apr 18 '16 at 2:19
  • $\begingroup$ I can only see unprotecting UpTo and assigning the above up value to it. $\endgroup$ – Edmund Apr 18 '16 at 2:53
  • 1
    $\begingroup$ @M.R. Updated for overload of UpTo so that you don't have to change your code. With the usual warnings on unprotecting an altering built-in functions. $\endgroup$ – Edmund Apr 18 '16 at 3:03

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.