Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct syntax for this ReplaceAll on a list of lists?

A light-weight question for the experts. I can't seem to figure the correct syntax to this replacement. I have this list

Clear[a, b, c, d]
polesList = {{3, {a, b}}, {5, {c, d}}};

It is of the form of a list with sublists each have the form {order,{x,y}} and I want to generate a new list of this form (x+y)^order

Currently this is what I do, which works:

((#[[2, 1]] + #[[2, 2]])^#[[1]]) & /@ polesList

(* ----->   {(a + b)^3, (c + d)^5}  *)  

But I have been trying to learn to use ReplaceAll as it is more clear to me than pure functions, since I can see the pattern better, like this:

Clear[a, b, c, d, n]
polesList = {{3, {a, b}}, {5, {c, d}}};
ReplaceAll[polesList, {n_, {x_, y_}} :> (x + y)^n]   (*I thought this will work*)

I get strange result, which is

{(5 + c)^3, {(5 + d)^a, (5 + d)^b}}

What is the correct syntax to do this replacement using ReplaceAll instead of the pure function method?

Thanks

Update:

I find that using Replace, instead of ReplaceAll works, but need to say {1} at the end:

Clear[a, b, c, d, n]
polesList = {{3, {a, b}}, {5, {c, d}}};
Replace[polesList, {n_, {x_, y_}} :> (x + y)^n, {1}]

which gives

{(a + b)^3, (c + d)^5}

But ReplaceAll does not take {1} at the end. I am more confused now which to use :)

like image 463
Nasser Avatar asked Aug 01 '11 02:08

Nasser


3 Answers

The problem is that ReplaceAll inspects all levels of the expression when looking for replacements. The entire expression matches the pattern {n_, {x_, y_}} where:

n matches {3, {a, b}}

x matches 5

y matches {c, d}

So you end up with (5 + {c , d}) ^ {3, {a, b}} which evaluates to the result you see.

There are a few ways to fix this. First, you can change the pattern so that it does not match the outermost list. For example, if the n values are always integers you could use:

ReplaceAll[polesList, {n_Integer, {x_, y_}} :> (x + y)^n]

Or, you could use Replace instead of ReplaceAll, and restrict the pattern matching the first level only:

Replace[polesList, {n_, {x_, y_}} :> (x + y)^n, {1}]

I find that applying replacement rules to the first level of a list is very common. It so happens that Cases, by default, only operates on that level. So I find myself frequently using Cases for level one replacements when I know that all elements will match the pattern:

Cases[polesList, {n_, {x_, y_}} :> (x + y)^n]

This last expression is how I would probably write the desired replacement. Keep in mind, though, that if all elements do not match the pattern, then the Cases approach will drop the mismatches from the result.

like image 175
WReach Avatar answered Jan 03 '23 15:01

WReach


The problem is that ReplaceAll looks at all levels in the expression and the first match to the pattern

{n_, {x_, y_}}

in the expression {{3, {a, b}}, {5, {c, d}}} is

{ n=={3, {a, b}}, {x==5, y=={c, d}}}

(if that notation is clear)

So you got the "strange" result

(5 + {c,d})^{3, {a, b}} == {5+c, 5+d}^{3, {a, b}} 
== {(5+c)^3, (5+d)^{a, b}} == {(5+c)^3, {(5+d)^a,(5+d)^b}}

The easiest fix, if n is always numeric, is

In[2]:= {{3, {a, b}}, {5, {c, d}}} /. {n_?NumericQ, {x_, y_}} :> (x + y)^n
Out[2]= {(a + b)^3, (c + d)^5}

Where I used the shorthand /. for ReplaceAll.


It might be that using Replace at level 1 is the best option

In[3]:= Replace[{{3, {a, b}}, {5, {c, d}}}, {n_,{x_,y_}}:>(x+y)^n, {1}]
Out[3]= {(a+b)^3,(c+d)^5}

which should be compared with the default replace that works at the top level {0}

In[4]:= Replace[{{3, {a, b}}, {5, {c, d}}}, {n_,{x_,y_}}:>(x+y)^n]
Out[4]= {(5+c)^3,{(5+d)^a,(5+d)^b}}
like image 30
Simon Avatar answered Jan 03 '23 14:01

Simon


You could also use ReplaceAll[ ] with Map:

Map[ReplaceAll[#, {n_, {x_, y_}} :> (x + y)^n] &, polesList]

or (using shorthands increasingly)

ReplaceAll[#, {n_, {x_, y_}} :> (x + y)^n] & /@ polesList

or

# /. {n_, {x_, y_}} :> (x + y)^n & /@ polesList
like image 20
Dr. belisarius Avatar answered Jan 03 '23 15:01

Dr. belisarius