11
$\begingroup$

In order to sort alphanumeric-as-string data of the form {"T3", "T14", "T1", "E2"}, so that "T14" comes after "T3", SortBy requires the tiebreaker function list:

{StringTake[#, 1] &, ToExpression@StringDrop[#, 1] &}

Which works as intended when this expression is inserted literally in SortBy. However, defining a utility function

mySort[x_String]:={StringTake[x, 1] , ToExpression@StringDrop[x, 1]}

doesn't work since the output is a list of expressions rather than a list of functions.

The alternative - to define a function via

mySort := {StringTake[#, 1] &, ToExpression@StringDrop[#, 1] &}

only works when the list to be sorted is 1-dimensional (as above) but not with lists of the form data2={"T3"->a, "T14"->b, "T1"->c, "E2"->d} where it is necessary to use SortBy[data2,mySort[#[[1]]]&].

Any alternatives that will work for general expressions?

$\endgroup$
2
  • $\begingroup$ I edited the previous typo, but it results in "T14" before "T3". Do you have the opposite? $\endgroup$ Commented Jun 20, 2012 at 20:08
  • $\begingroup$ Oh, you're right. Forget my previous comment. $\endgroup$
    – Heike
    Commented Jun 20, 2012 at 20:09

1 Answer 1

15
$\begingroup$

I think this question admits an elegant solution. Here is my attempt: define a special wrapper:

ClearAll[sortFun];
sortFun /: SortBy[expr_, sortFun[funs_List, partFun_]] :=
   SortBy[expr, Map[Composition[#, partFun] &, funs]];

Now,

mySort := {StringTake[#, 1] &, ToExpression@StringDrop[#, 1] &}

and

SortBy[{"T3","T14","T1","E2"}, sortFun[mySort, Identity]]

(*   {E2,T1,T3,T14}  *)

while

SortBy[{"T3"->a,"T14"->b,"T1"->c,"E2"->d}, sortFun[mySort, First]]

(*  {E2->d,T1->c,T3->a,T14->b} *)

EDIT

Perhaps more elegantly

ClearAll[sortFun];
sortFun /: SortBy[expr_, sortFun[funs_List, partFun_]] :=
   SortBy[expr, Thread[Composition[funs, partFun]]];

and just for fun, another version:

ClearAll[sortFun];
sortFun /: call : SortBy[expr_, sortFun[funs_List, partFun_]] :=
   Block[{sortFun = Thread[Composition[##]] &}, call];
$\endgroup$
11
  • $\begingroup$ Superior to mine, +1 $\endgroup$
    – Rojo
    Commented Jun 20, 2012 at 20:09
  • $\begingroup$ @Rojo Thanks :) We seem to be thinking very similarly :) $\endgroup$ Commented Jun 20, 2012 at 20:10
  • 1
    $\begingroup$ @alancalvitti I actually don't find carrying sortFun around a big burden. It is a very general wrapper, and it minimally changes the syntax. One can use some shorter name if sortFun is too long. One could also add rules to SortBy, but I'd rather not do it. $\endgroup$ Commented Jun 20, 2012 at 20:24
  • 1
    $\begingroup$ @alancalvitti Thanks for the accept. As for elegance, it seems that we have somewhat different perceptions on that (which is just fine, this is a very subjective matter). I feel that the first solution in the edit is the most elegant, and will be hard-pressed to see anything simpler than that. $\endgroup$ Commented Jun 20, 2012 at 21:47
  • 1
    $\begingroup$ @alancalvitti This will then be either a more narrow, point solution (since functions can also be represented as symbols, composite heads with sub-values, etc), or will be really complex and would require compile stage to be efficient. I do not exclude that this is possible, but I think that my solution captures the mathematical essence of the problem, which is, function's composition. And when possible, I value mathematical clarity over what may look like a better usability, because a real usability is in supporting the right abstractions. $\endgroup$ Commented Jun 20, 2012 at 22:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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