Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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?

share|improve this question
add comment

4 Answers

up vote 7 down vote accepted

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}}
share|improve this answer
    
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 1:18
add comment

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}]
share|improve this answer
add comment

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}]
share|improve this answer
    
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}] –  rainer Mar 12 '13 at 10:25
1  
@rainer Like Cases[6*g[1]*g[2]*g[3], g[x_] -> x, 2] ? –  b.gatessucks Mar 12 '13 at 10:44
    
@Mr.Wizard Thanks for pointing out what the OP wanted, your solution is elegant +1. –  Artes Mar 12 '13 at 11:23
    
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? –  Mr.Wizard Mar 12 '13 at 11:24
add comment
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}]*)
share|improve this answer
    
I had almost the same: expr /. Times[a___ : 1, x : __g] :> a func@Join@x /. g -> List –  Simon Woods Mar 13 '13 at 10:07
    
@Simon, just noticed that i could save a character using __g instead of ___g :) –  kguler Mar 13 '13 at 10:46
    
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. –  Mr.Wizard Mar 13 '13 at 11:13
    
@Mr.Wizard, Thanks for the edit and the vote. –  kguler Mar 13 '13 at 11:33
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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