Correct slot assignment when mapping from different lists using pure function

Given

expr = u == a1 + a2 x + a3 y;


and

uRep = {u1, u2, u3};
xyRep = {{x1, y1}, {x2, y2}, {x3, y3}};


I'd like to generate 3 equations

{u1 == a1 + a2 x1 + a3 y1,
u2 == a1 + a2 x2 + a3 y2,
u3 == a1 + a2 x3 + a3 y3}


By replacing u with u1,u2,u3 at a time, and at same time, replace x with x1,x2,x3 and the same for y

Currently I do this using MapThread with explicit Function like this:

MapThread[Function[{z1, z2}, eq1 /. {u -> z1, x -> z2[[1]], y -> z2[[2]]}], {uRep, xyRep}]


But I was wondering what the syntax would be do it using pure function. I tried

MapThread[eq1 /. {u -> #1[[1]], x -> #2[[1]], y -> #2[[2]]} &, {uRepl, xyRepl}]
eq1 /. {u -> #1[[1]], x -> #2[[1]], y -> #2[[2]]} & @@@ {uRepl, xyRepl}


and few others. They all produce errors due to wrong slot # mapping.

I am happy with the Function solution, but was wondering what the syntax will be using pure function. (I looked at many related questions, but could not find solution to apply for this case, I am sure I missed something)

• Nasser, as a matter of personal curiosity may I know why you did not Accept my answer. To my eye it is the nicest way, and I would like to know why you do not like it. I ask this sincerely. Jun 6, 2014 at 5:56
• @Mr.Wizard all the answers were great and I +1 them all and would have accepted them all if I could. When all answers are good and I do not know which to accept, I normally accept the one which people have voted most to at the time. That is all. if there are two answers with same votes and both equally good, I flip a coin. Thanks again for your excellent answers as always. Jun 6, 2014 at 23:34
• You are welcome, as always. Thanks for satisfying my curiosity. Jun 7, 2014 at 2:49

MapThread[ expr /. {u -> #1, x -> #2[[1]], y -> #2[[2]]} &, {uRep, xyRep}]


works as expected. So do

(expr /. {u -> #1, x -> #2[[1]], y -> #2[[2]]}) & @@@  Transpose[{uRep, xyRep}]


and

(expr /. Thread[{u, x, y} -> ##]) & /@ (Flatten /@ Transpose[{uRep, xyRep}])


All three give

{u1 == a1 + a2 x1 + a3 y1, u2 == a1 + a2 x2 + a3 y2, u3 == a1 + a2 x3 + a3 y3}

• ah! I was close. I was doing #1[[1]] all along for the first argument instead of just #1, since I also used #2[[...]] for the other argument! I did not notice [[...]] is not needed for the first one (now I know what the error meant :) Jun 4, 2014 at 2:16
• @Nasser, the error message should have given a hint :)
– kglr
Jun 4, 2014 at 2:17
• That is why I think the Function method was more clear. Arguments are defined using normal symbols, and in fixed location and position, so less chance of making a syntax error, and it looks more natural than using pure function with its # this and #1 that. I am trying to learn to use Function[...] more now than pure functions, even though it takes few more keystrokes to write it. Jun 4, 2014 at 2:27

May this would be easier

list = MapThread[Prepend, {xyRep, uRep}];
#1 == a1 + a2 #2 + a3 #3 & @@@ list

(*
{u1 == a1 + a2 x1 + a3 y1, u2 == a1 + a2 x2 + a3 y2,
u3 == a1 + a2 x3 + a3 y3}
*)


I propose destructuring:

MapThread[
{##} /. {u_, {x_, y_}} -> expr &,
{uRep, xyRep}
]

{u1 == a1 + a2 x1 + a3 y1, u2 == a1 + a2 x2 + a3 y2, u3 == a1 + a2 x3 + a3 y3}


Note the express use of Rule rather than the normal RuleDelayed, which allows expr to evaluate.

If expr will be input in the form given I feel this is the cleanest approach.

Here are two more ways;

uRep = {u1, u2, u3};
xyRep = {{x1, y1}, {x2, y2}, {x3, y3}};

f = #1 == a1 + a2 #2 + a3 #3 &;

MapThread[f[#1, #2[[1]], #2[[2]]] &, {uRep, xyRep}]


Both of the MapThread expressions give
{u1 == a1 + a2 x1 + a3 y1, u2 == a1 + a2 x2 + a3 y2, u3 == a1 + a2 x3 + a3 y3}