3
$\begingroup$

Is there a way to extract the arguments of a function? Consider the following example:

I have this sum

g[1] + g[2] + g[3] + g[1]*g[3] + 3*g[1]*g[2] + 6*g[1]*g[2]*g[3]

Now, what I want to do is exctract the function arguments and apply them to another function func which takes the arguments as a list.

func[{1}] + func[{2}] + func[{3}] + func[{1, 3}] + 3*func[{1, 2}] + 6*func[{1, 2, 3}]

I know there is Extract[g[1]*g[3], Position[g[1]*g[3], _Integer]] but that does not work if I have a multiplicative constant.

Is there a way to do this?

$\endgroup$

4 Answers 4

7
$\begingroup$

The pattern for a direct replacement proves to be a bit tricky:

start = g[1] + g[2] + g[3] + g[1]*g[3] + 3*g[1]*g[2] + 6*g[1]*g[2]*g[3];

start /. y__g z_g | y__g x_. :> x func[Join @@ List @@@ {y, z}]
func[{1}] + func[{2}] + func[{3}] + 3 func[{1, 2}] + func[{1, 3}] + 6 func[{1, 2, 3}]

If order doesn't matter, and arguably it shouldn't with Times you could use:

start //. g[x__] g[y__] :> g[x, y] /. g[x__] :> func[{x}]
func[{1}] + func[{2}] + func[{3}] + 3 func[{1, 2}] + func[{1, 3}] + 6 func[{3, 1, 2}]

The OP asked how to extract just the arguments of g and do so preserving the order of the input. This requires wrapping the expression in Hold (or similar) before it is evaluated, to prevent the automatic sorting of Plus. I shall use a variation of kguler's cleaner patten, and Cases since we want only parts of the expression and not the entire thing transformed. I shall scan at level 2 (rather than the default level 1) to bypass the additional Head.

start2 = Hold[g[1] + g[2] + g[3] + g[1]*g[3] + 3*g[1]*g[2] + 6*g[1]*g[2]*g[3]]

Cases[start2, (x___ : 1) p__g :> First /@ {p}, {2}]
{{1}, {2}, {3}, {1, 3}, {1, 2}, {1, 2, 3}}

Let me take this opportunity to show an unusual but potentially useful method I also used for Convert head Times to List. You can hold your expression unevaluated by using SetDelayed, but normally it is fully evaluated when it is called. (This has the advantage of letting you use the expression elsewhere without additional effort such as ReleaseHold.) To get around that when doing the extraction you can Block the functions that you do not want to evaluate during the call. Example:

start3 := g[1] + g[2] + g[3] + g[1]*g[3] + 3*g[1]*g[2] + 6*g[1]*g[2]*g[3]

Block[{Plus},
  Cases[start3, (x___ : 1) p__g :> First /@ {p}]
]
{{1}, {2}, {3}, {1, 3}, {1, 2}, {1, 2, 3}}

Alternatively, you could use my step evaluator function to get the unevaluated expression wrapped in HoldForm, then use level 2 again:

Cases[step @ start3, (x___ : 1) p__g :> First /@ {p}, {2}]
{{1}, {2}, {3}, {1, 3}, {1, 2}, {1, 2, 3}}
$\endgroup$
4
  • $\begingroup$ Wizard! Thanks, the first solution really helps me. Do u maybe know how to get just the arguments in a list: just {{1},{2},{3},{1,2},{1,3},{1,2,3}} like in the example? $\endgroup$
    – rainer
    Commented Mar 14, 2013 at 18:49
  • $\begingroup$ @rainer I don't know why you say "like in the example" as your example is clearly the form that I show in my answer. If however you want the argument-only list you could do: Cases[start, (x___ : 1) p__g :> First /@ {p}] (based on kguler's answer). Note that the output is not in the same order that you show because the terms are automatically sorted by Plus before Cases even sees them. If that is a problem you will need to define start using Hold. Ask if you need help. $\endgroup$
    – Mr.Wizard
    Commented Mar 14, 2013 at 19:08
  • $\begingroup$ thank you. yes just the argument-only list, but I need it to be in the same order. How can I use 'Hold' here? $\endgroup$
    – rainer
    Commented Mar 14, 2013 at 21:13
  • $\begingroup$ @rainer I added several examples that I hope you will find of use and interest. $\endgroup$
    – Mr.Wizard
    Commented Mar 15, 2013 at 1:18
5
$\begingroup$

Would this do, or does the ordering matter?

    Clear@func
    func /: func[a_] func[b_] := func[Flatten@{a, b}]
    g[1] + g[2] + g[3] + g[1]*g[3] + 3*g[1]*g[2] + 6*g[1]*g[2]*g[3]/. g[a_] -> func[{a}]
$\endgroup$
3
$\begingroup$

Use ReplaceAll (/.)

g[1] + g[2] + g[3] + g[1]*g[3] + 3*g[1]*g[2] + 6*g[1]*g[2]*g[3] /. g -> func
func[1] + func[2] + 3 func[1] func[2] + func[3] + func[1] func[3] 
        + 6 func[1] func[2] func[3]

Edit

g[1] + g[2] + g[3] + g[1]*g[3] + 3*g[1]*g[2] + 6*g[1]*g[2]*g[3] /. { 
g[a_]*g[b_]*g[c_] -> func[{a, b, c}], g[a_]*g[b_] -> func[{a, b}], g[a_] -> func[{a}]}
func[{1}] + func[{2}] + func[{3}] + 3 func[{1, 2}] + func[{1, 3}] + 6 func[{1, 2, 3}]
$\endgroup$
4
  • $\begingroup$ thanks,I figured that out already, but thats not exactly what I want to do: I want to transform e.g.6*g[1]*g[2]*g[3] into 6*func[{1,2,3}] $\endgroup$
    – rainer
    Commented Mar 12, 2013 at 10:25
  • 1
    $\begingroup$ @rainer Like Cases[6*g[1]*g[2]*g[3], g[x_] -> x, 2] ? $\endgroup$ Commented Mar 12, 2013 at 10:44
  • $\begingroup$ @Mr.Wizard Thanks for pointing out what the OP wanted, your solution is elegant +1. $\endgroup$
    – Artes
    Commented Mar 12, 2013 at 11:23
  • $\begingroup$ Thanks for the vote. I wonder if the question is intended to be more general than the example given. Are the functions Plus and Times arbitrary? $\endgroup$
    – Mr.Wizard
    Commented Mar 12, 2013 at 11:24
3
$\begingroup$
expr = g[1] + g[2] + g[3] + g[1]*g[3] + 3*g[1]*g[2] + 6*g[1]*g[2]*g[3];
expr /. Times[x___:1 , p__g] :> x func[{p}[[All, 1]]]
(* func[{1}] + func[{2}] + func[{3}] + 3 func[{1, 2}] + func[{1, 3}] + 6 func[{1, 2, 3}]*)
$\endgroup$
4
  • $\begingroup$ I had almost the same: expr /. Times[a___ : 1, x : __g] :> a func@Join@x /. g -> List $\endgroup$ Commented Mar 13, 2013 at 10:07
  • $\begingroup$ @Simon, just noticed that i could save a character using __g instead of ___g :) $\endgroup$
    – kglr
    Commented Mar 13, 2013 at 10:46
  • $\begingroup$ I would have sworn I tried that pattern and it didn't work. Anyway, nice work. I hope you don't mind my edit but your code was invalid syntax in v7 and All works for both. $\endgroup$
    – Mr.Wizard
    Commented Mar 13, 2013 at 11:13
  • $\begingroup$ @Mr.Wizard, Thanks for the edit and the vote. $\endgroup$
    – kglr
    Commented Mar 13, 2013 at 11:33

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.