Is there an elegant way to sort the arguments of Times in e.g. TraditionalForm so that factors go to the front and state variables to the back? Are there methods to prevent certain transformations, like moving everything into the numerator as in the example?

par = {p, k, Subscript[k, a], Subscript[k, b]};
expr = -A Subscript[k, b] B p k (1 - p) 1/(B + A) Subscript[k, a]

$-\frac{A \ B \ k \ (1-p) \ p \ k_a \ k_b}{A+B}$

What I would like to see is that symbols are ordered according to their appearance order in par, symbols not specified are sent to the back and fractions are not transformed at all, something like this:

$-(1-p) \ p \ k \ k_a \ k_b \ \frac{1}{A+B} \ A \ B$

There are many problems when manually sorting arguments of Times (here I only did a reversal for sake of simplicity):

expr /. Times[x_, y__] :> ((Inactive@Times) @@ Reverse[{x, y}])


for example unnecessary *-s and numerical factors like -1 explicitly displayed.

  • $\begingroup$ Interesting question, but I have the feeling we had one like this before. Can't find it at the moment, though. $\endgroup$ Jul 21, 2015 at 14:02
  • $\begingroup$ @Sjoerd I had the same feeling, and you can imagine that I took the time to look for it. BTW, I find it very strange that a complex typesetting environment like Mathematica does not provide this functionality readily and one has to hack his way like jkuczm did... $\endgroup$ Jul 21, 2015 at 18:35
  • $\begingroup$ Related: (9570) $\endgroup$
    – Mr.Wizard
    Jul 21, 2015 at 21:36
  • $\begingroup$ Thanks @Mr.Wizard, that is the one I was looking for. Accordingly, mine is a duplicate then. $\endgroup$ Jul 21, 2015 at 21:59
  • 1
    $\begingroup$ @Mr.Wizard Wait! On second thought, I ask for more time to evaluate the differences. One of my concerns (not worded above) was that the output must be readily convertible by TeXForm and I'm not sure Row-s in Silvia's answer are ok with TeX. Will check it tomorrow all your answers, have to sleep now. $\endgroup$ Jul 21, 2015 at 22:07

2 Answers 2


You can create your own ...Form wrapper that will format Times as you want it.

Let's start with ordering function that can be used in SortBy. It puts numeric coefficients in front, expressions present in par are ordered according to their position in par, all other expressions are moved to the end.

ClearAll[par, order]
par = {(1 - p), p, k, Subscript[k, a], Subscript[k, b]};
order[_?NumericQ] := 0
order[x_] := Replace[Position[par, x, {1}, 1], {{i_}} :> i]

Now a small helper "wrapper" that will vanish after conversion to boxes. It will also remove boxes resulting from HoldForm used directly inside wrapper.

MakeBoxes[vanishingWrapper[expr_], form_] ^:= MakeBoxes[expr, form];
MakeBoxes[vanishingWrapper[HoldForm[expr_]], form_] ^:= 
    First@MakeBoxes[HoldForm[expr], form];

Now the main ...Form function that, when converted to boxes, wraps some sub-expressions with our vanishingWrapper:

MakeBoxes[istvanForm[expr_], _] ^:=
        {heldExpr =
            HoldComplete[expr] /. HoldPattern[Times][args__] :>
                    {eval =
                            {heldArgs = 
                                    SortBy[HoldComplete[args], order], 
                                    pow_Power :> vanishingWrapper[pow],
                            ] @@ heldArgs
                    eval /; True
        Function[Null, MakeBoxes[#, TraditionalForm], HoldAllComplete] @@

When Times function is converted to TraditionalForm boxes, its arguments are sorted, unless Times is inside HoldForm. This sorting is done in addition to ordinary sorting, occurring due to Orderless attribute, when Times is evaluated. To prevent this additional sorting, istvanForm wraps Times with HoldForm and vanishingWrapper. So we get boxes coming from HoldForm[Times[...]], but thanks to vanishingWrapper all additional boxes from HoldForm are gone, so when we copy resulting expression there will be no HoldForm inside it.

When Power expression, with negative numeric exponent, is found directly inside Times, it triggers special formatting rules putting everything in one fraction. To prevent this special formatting, istvanForm wraps all Power expressions on first level of Times with vanishingWrapper. So that, when expression is converted to boxes, special formatting is not triggered.

To make istvanForm behave like proper ...Form wrapper we must add it to $OutputForms:

If[FreeQ[$OutputForms, #, {1}],
    PrependTo[$OutputForms, #];
]& @ istvanForm

Now let's see istvanForm in action:

-A Subscript[k, b] B p k (1 - p) 1/(B + A) Subscript[k, a] // istvanForm

istvanForm usage

  • $\begingroup$ The only occasion when a user-defined function should start with a capital letter! +1 : ) $\endgroup$ Jul 21, 2015 at 18:34
  • $\begingroup$ @IstvánZachar I promise to capitalize your name next time I use it in a function ;) $\endgroup$
    – jkuczm
    Jul 21, 2015 at 19:48

I shall adapt my code from How do I reassign canonical ordering of symbols? with the addition of a rule for the Power[_, -1] form. I assume that any Variables not in par are to be placed at the end.

reorderIstván[expr_, par_List] :=
 Module[{h, rls},
   rls = MapIndexed[x : # :> h[#2, Replace[x, rls, -1]] &, 
     DeleteDuplicates @ Join[par, Variables @ expr] ];
   HoldForm @@ {expr /. rls} //. h[_, x_] :> x /. 
    x_^-1 :> RawBoxes @ FractionBox["1", ToBoxes[x]]


par = {p, k, Subscript[k, a], Subscript[k, b]};
expr = -A Subscript[k, b] B p k (1 - p) 1/(B + A) Subscript[k, a];

reorderIstván[expr, par]
-(1 - p) p k Subscript[k, a] Subscript[k, b] A B 1/(A + B)
reorderIstván[expr, par] // TeXForm

$-(1-p) p k k_a k_b A B \frac{1}{A+B}$

  • $\begingroup$ I got the time to advance with this problem. My issue with your approach is that due to the HoldForm-s, one cannot do post replacements like reorderIstván[expr, par] /. x_Symbol :> If[Context@x === "Global`", f@x, x]. I haven't figured a way to bypass this yet... any idea? I'd rather avoid including this transformation directly into the reordering function. $\endgroup$ Aug 17, 2015 at 10:22
  • $\begingroup$ @IstvánZachar does reorderIstván[expr, par] /. x_Symbol :> RuleCondition@If[Context@x === "Global", f@x, x]` give what you want or are you looking for something else? (See mathematica.stackexchange.com/a/29319/121 if you are unfamiliar with RuleCondition.) $\endgroup$
    – Mr.Wizard
    Aug 17, 2015 at 11:08
  • $\begingroup$ Ok, RuleCondition did the job, thanks. I knew (and forgot) about it but never used before. $\endgroup$ Aug 17, 2015 at 11:42

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.