update:
Thanks for the answers below. But I noticed they do not handle the following special cases: lis=1
and lis=z
, lis=1/z
and lis=-z
as these are also considered legal input as given in the question below. It is easy to add special case processing for these, by making them lis={1}
and lis={z}
etc... before calling the parser (this is what I actually had to do myself). but it will be nice if this was incorporated as special pattern/rule as well. I could not do it myself inside Alternative
and had to check for this before as special case.
To make sure what is the input, I'll clarify it again: Each term is of the form c*z^n
where there can be one or more terms. i.e. lis= term1+term2+term3...
In each term, c
can be any numerical value, and n
can be any numerical value (positive or negative). The result will be list of {{c,n},.....}
, one entry for each term. Even if there is one term only, it should work.
Examples to verify against:
lis=1 ---> {{1,0}}
lis=z ----> {{1,1}}
lis=-z --->{{-1,1}}
lis=1/z ---->{{1,-1}}
lis=1+z^-1 --->{{1,0},{1,-1}}
lis=1/z^3 + 3/z + 3 z + z^3 -->{{1,-3},{3,-1},{3,1},{1,3}}
lis=6 + 1/z^4 + 4/z^2 + 4 z^2 + z^4 -->{{6, 0}, {1, -4}, {4, -2}, {4, 2}, {1, 4}}
Original question
The hammer I use now for everything I see that needs parsing with patterns is Cases
.
So, I was trying to write a simple pattern based parser that accepts any output from Expand(f[z])
where f[z]
is rational function of z
only. For example, it take such input as
Expand[(z + 1/z)^4]
(*6 + 1/z^4 + 4/z^2 + 4 z^2 + z^4*)
or
Expand[(z + 1/z)^3]
(*1/z^3 + 3/z + 3 z + z^3*)
or 1
or z
or z^-1
or 1+z
and so on. So the input can be thought of as power series in z
. All terms are in this form. So it is well defined what it is.
The output of the parser will be a list that shows the coefficient of each term, and the exponent of z
. So given the input 6+(1/z^4) + 4/z^2 + 4 z^2 + z^4
the output will be
{{6,0},{1,-4},{4,-2},{4,2},{1,4}}
The best I can come up with is this:
lis = 6 + 1/z^4 + 4/z^2 + 4 z^2 + z^4
Cases[lis, Alternatives[x_. Power[z, e_.],
Times[x_, Power[z, e_.]],
x_.] :> {x, e}]
The problem is that the above generates
{{6},{1,-4},{4,-2},{4,2},{1,4}}
and not
{{6,0},{1,-4},{4,-2},{4,2},{1,4}}
This is because the pattern that matched x_. (the last one in the Alternatives
does not have an e
in it, and Mathematica replaced the e
with the Null sequence as documented in help. Another problem with the above, is that x_.
has to the last one in the alternatives. If I had wrote this instead:
Cases[lis, Alternatives[x_., x_. Power[z, e_.], Times[x_, Power[z, e_.]]] :>
{x, e}]
Then it would not have worked (another thing to worry about).
Ok, this is all fine, except now the output is not symmetric and needs special case processing.
What I was hoping to do is something like this
Cases[lis, Alternatives[x_. Power[z, e_.] :> {x,e} ,
Times[x_, Power[z, e_.]] :> {x,e},
x_. :> {x,0}]
]
ie. have a specific rule for each specific pattern. The above is much easier to work with, since now I can specific the output for each pattern instead of having all pattern target one output. But the above of course is not valid Mathematica code and Cases
does not like it.
Are there such general ways of doing the pattern matching that allows one to write specific rules for specific pattern? It does not have to use Cases
as long as it follows this general approach.
I know that one can probably use the Polynomial specific functions (such as CoefficientRules
, CoefficientList
, and related functions to do this for this case, but I am more interested in this general approach so I can learn how to use it for things other that this example)