# List reversion inspired by Python

In python, if you wish to reverse a list, here is the trick:

range(10)[::-1]  => [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


Note: list[start:end:steps] is the slice method in python. The above code omitted the first two arguments.

It rings a bell in Mathematica:

Part[list, Span[start, end, step]] <=> list[[start;; end;; step]]


However this isn't gonna work in MMA (or not yet? since mine is still MMA 7)

Range[10][[;; ;; -1]]


Part::take: Cannot take positions 1 through -1 in {1,2,3,4,5,6,7,8,9,10}. >>
Part[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1 ;; All ;; -1]

This error message gave clues to what happened. When step length is negative, the start index should be greater than the end one - no matter in python or MMA syntax.

The problem why this didn't work lies in the omitted arguments. MMA filled them with 1 and All and then got stuck. By contrast python smartly exchanged the two.

My actual question in this is: How can I can look into the default values /optional arguments of a built-in function like Span? I can't find it in the documentations.

Give another look at the fun code: range(10)[::-1]

My implementation of this it to modify the definitions

Unprotect[Span, Part];
Part[x_List, Span[1, All, k_]] /; k < 0 := Part[x, Span[All, 1, k]];
Protect[Span, Part]

(*behold lol*)

Range[10][[;; ;; -1]]
(* {10, 9, 8, 7, 6, 5, 4, 3, 2, 1} *)


To clear the modifications:

Unprotect[Span, Part]; Clear[Span, Part]; Protect[Span, Part]


or

CompoundExpression@@ Through[{Unprotect, Clear, Protect}[Span, Part]]

-
Is there a reason that you don't want to use the Reverse command? –  Mark McClure Mar 29 '13 at 13:35
Nope, it's a just-because-I-could situation. And "Reverse@" is still shorter than "[[;;;;-1]]". :p –  秦紀維 Mar 29 '13 at 13:38
This works: Range[10][[10 ;; 1 ;; -1]]. It's not an idiom I've used, but found it pretty easily in the documentation. –  Mark McClure Mar 29 '13 at 13:44
And in case your list is of unknown length, you can change @MarkMcClure's idiom to [[-1 ;; 1 ;; -1]] to reverse it –  rm -rf Mar 29 '13 at 14:21
Why wouldn't you use Range[9, 0, -1]? –  m_goldberg Mar 30 '13 at 3:06

To answer your question: In this case you could just type a fake Span call and keep it unevaluated. When you then look at the fullForm you see:

Hold[list[[ ;; ;;-1]]]//FullForm

(* Hold[Part[list,Span[1,All,-1]]] *)


what you actually called: Span[1,All,-1].

Since you now know what happens, you can catch, when someone calls Part[list_, Span[1, All, -1] and use Reverse to give the reversed list

Unprotect[Span];
Span /: Part[list_, Span[1, All, -1]] := Reverse[list];
Protect[Span]


and now your simple example works as expected

Range[10][[;;;;-1]]
(* {10,9,8,7,6,5,4,3,2,1} *)

-
Pardon me, but isn't this basically already in the question? –  Mr.Wizard Mar 29 '13 at 19:16
@Mr.Wizard The question was, how to find out to what Span[[;;;;-1]] is evaluated. I updated my answer later to show how to use Upvalues and Reverse. And yes, all details were already implicitly given in the question. The only part I added was how get to what list[[;;;;-1]] is evaluated. –  halirutan Mar 29 '13 at 22:20
is the generalization to arbitrary negative increments Reverse[list][[;;;;Abs[inc]]] or Reverse[list[[;;;;Abs[inc]]]] ? Anybody sure without trying it..? –  george2079 Mar 31 '13 at 16:49

Your python idiom can be implemented in Mathematica using Part and Span as:

Range[10][[-1;;1;;-1]]
(* {10, 9, 8, 7, 6, 5, 4, 3, 2, 1} *)


which is very similar to your python command, and doesn't require you to unprotect either Span or Part.

-
This is nice, but somehow I don't think the OP is unaware of this as he knew how to write the equivalent. Rather, this question is about low-level defaults, is it not? Isn't Span just an illustration? –  Mr.Wizard Mar 29 '13 at 19:18
I don't think they're aware of negative indices, and what they wrote — [[;; ;; -1]] — is not an equivalent. I don't see this as low level defaults question, because no defaults are being used here. ;; is explicit for "all elements" (;; and All are mentioned in the Part docs), and this is just a matter of being confused by seeing 1 and All in the fullform used in the error. In other words, I don't think this has to do with mysterious defaults in the same way that Slot[1] for # is not using a hidden default of 1. –  rm -rf Mar 29 '13 at 19:40
Okay. By the way I meant Span[All, 1, -1] as the equivalent, which he used. –  Mr.Wizard Mar 31 '13 at 0:04