3

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?

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
rainer
  • 401
  • 4
  • 12

4 Answers4

7

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}}
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • 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? – rainer Mar 14 '13 at 18:49
  • @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. – Mr.Wizard Mar 14 '13 at 19:08
  • thank you. yes just the argument-only list, but I need it to be in the same order. How can I use 'Hold' here? – rainer Mar 14 '13 at 21:13
  • @rainer I added several examples that I hope you will find of use and interest. – Mr.Wizard Mar 15 '13 at 01:18
5

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}]
gpap
  • 9,707
  • 3
  • 24
  • 66
3

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}]
Artes
  • 57,212
  • 12
  • 157
  • 245
3
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}]*)
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
kglr
  • 394,356
  • 18
  • 477
  • 896