I want to mimic the functionality of Collect[expr, {vars}, func], but with the following modification: The function f that is applied to each coefficient is different, and depends on which variable it is a coefficient of. The vars are expressions of predetermined known heads (which in the example below are _e, _f, _g, _h).


expr = -2 x e[x] + x e[y] + x^2 e[x] + y e[x] + y e[y] + x^2 f[x] + y^2 f[x] + x^2 g[x] + y^2 h[x]
  1. I need to collect expr by e[_], f[_], g[_] and h[_].

  2. Apply simpE to the coefficients of e[_], and simpF to the coefficients of f[_], and simpGen to the coefficient of everything else.

  3. This needs to work even when certain terms are absent from expr. e.g. if expr doesn't have any e[_] etc.

My idea (which doesn't work) is to do this in two steps:

  1. First collect the expression:

    Collect[expr, {_f, _e, _g, _h}]
  2. Then replace with the rule that makes the transformation on each coefficient.

    rule = (Plus[
       Optional[Times[exprE_., funcE_e]], 
       Optional[Times[exprF_., funcF_f]], 
       rest_.]) :> 
    (simpE[exprE] funcE + simpF[exprF] funcF + Collect[rest,{_g, _h}, simpRest])

The (not quite correct) result is:

Collect[expr, {_f, _e, _g, _h}] /. rule

e[x] simpE[-2 x + x^2 + y] + f[x] simpF[x^2 + y^2] + g[x] simpRest[x^2] + h[x] simpRest[y^2] + simpRest[(x + y) e[y]]

But this doesn't work because

  1. the rule groups e[y] with the rest of the terms and incorrectly applies simpRest to it (see last term of output), instead of simpE[x+y] e[y].

  2. If certain terms are absent, then the rule doesn't even match. Consider expr2 below which is absent of f[_]:

    expr2 = -2 x e[x] + x^2 e[x] + y e[x] + x e[y] + y e[y] + x^2 g[x] + y^2 h[x] 

    The rule doesn't match:

    Collect[expr, {_f, _e, _g, _h}] /. rule

    (-2 x + x^2 + y) e[x] + (x + y) e[y] + x^2 g[x] + y^2 h[x]

I need help with this particular modification of Collect. Is there a sexy way to get this done?

  • $\begingroup$ Perhaps the function myCollect in this thread mathematica.stackexchange.com/questions/85479/… could help. It modifies collect to use a function not just of the coefficient but also of the term itself. You could then just use an if statement in the function you apply to differentiate the different terms. Don't know how sexy this is though. $\endgroup$
    – Jansen
    Commented Dec 28, 2015 at 14:29
  • $\begingroup$ I notice that you have not Accepted an answer. Do neither of the answers work as you would like? Could you include the exact output that you hope for from each example? $\endgroup$
    – Mr.Wizard
    Commented Jan 29, 2016 at 2:12
  • $\begingroup$ @Mr.Wizard ive been traveling, then got sick... Will come back when I get better $\endgroup$
    – QuantumDot
    Commented Jan 29, 2016 at 17:18
  • $\begingroup$ I am sorry to hear that you have been ill. I hope it is entirely temporary and you are well very soon. $\endgroup$
    – Mr.Wizard
    Commented Jan 29, 2016 at 21:49

3 Answers 3


Maybe the following. Simplifying a left-over constant term along with the other coefficients seems hard to comprise in a single, simple function.

forms = {_f, _e, _g, _h};
funcs = {simpF, simpE, simpG, simpH};
simpConstant[c_] := simpC[c];
Times[c_simpAll, form_] ^:= (c /. simpAll -> (form /. Thread[forms -> funcs])) form;

Collect[2 + expr, {_f, _e, _g, _h}, simpAll] /. simpAll -> simpConstant
Collect[2 + expr2, {_f, _e, _g, _h}, simpAll] /. simpAll -> simpConstant
Collect[2 + x, {_f, _e, _g, _h}, simpAll] /. simpAll -> simpConstant
  simpC[2] + e[y] simpE[x + y] + e[x] simpE[-2 x + x^2 + y] + 
   f[x] simpF[x^2 + y^2] + g[x] simpG[x^2] + h[x] simpH[y^2]

  simpC[2] + e[y] simpE[x + y] + e[x] simpE[-2 x + x^2 + y] + 
   g[x] simpG[x^2] + h[x] simpH[y^2]

  simpC[2 + x]


funs = {f, e, g, h}
apply = {sf, se, sgen, sgen}
k[a_, b_] := (Head@b /. Thread[funs -> apply])[a] b

Collect[z@x expr, Blank/@funs] /. (Times[a___, l: Blank@#, r___] :> k[a r, l] &/@funs)

e[y] se[(x + y) z[x]] +
e[x] se[(-2 x + x^2 + y) z[x]] + 
f[x] sf[(x^2 + y^2) z[x]] +
g[x] sgen[x^2 z[x]] + 
h[x] sgen[y^2 z[x]]

What about this. First you modify collect so that it doesn't group terms, and so the function acts not only on the coefficient but also on the variable, like so

myCollect[expr_, vars_, funct_ : (#1 #2 &)] := 
 Expand@Collect[expr, vars, fDummy] //. {a_ fDummy[x_] :> 
  fDummy[a, x], a_ fDummy[b_, x_] :> fDummy[a b, x]} /. 
  fDummy[x_] :> fDummy[1, x] /. fDummy -> funct

Then simply define

simp[arg_e, coeff_] := arg simpE[coeff]
simp[arg_f, coeff_] := arg simpF[coeff]
simp[arg_, coeff_] := arg simpGen[coeff]   

and apply:

myCollect[expr, {_f, _e, _g, _h}, simp]
(* e[y] simpE[x + y] + e[x] simpE[-2 x + x^2 + y] + 
f[x] simpF[x^2 + y^2] + g[x] simpGen[x^2] + h[x] simpGen[y^2] *)

or for the second case,

myCollect[expr2, {_f, _e, _g, _h}, simp]
(* e[y] simpE[x + y] + e[x] simpE[-2 x + x^2 + y] + g[x] simpGen[x^2] + 
 h[x] simpGen[y^2] *)

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.