# Replace elements in list not matching elements of another list at the same position

I would like to compare two arrays:

m = {a,b,c,d,d,f};
n = {b,b,a,d,d,e};


and get:

{0,b,0,d,d,0}


I have tried all kinds of things, like:

m = {a,b,c,d,d,f};
n = {b,b,a,d,d,e};
Transpose[{m, n}];
If[{x_ == y_} :> x, 0]


but clearly, I have no idea what I am doing! I am (obviously) very new to Mathematica, and would greatly appreciate any help.

-
Will the elements always be symbols, or will they sometimes be values, or characters/strings? – C. E. Oct 9 '13 at 17:16

The following solution may look a bit weird, but has an advantage of automatically being very efficient for numerical large lists:

m * (1 - Block[{Unitize}, _Unitize = 1; #] & [ Unitize[m - n]])

-
+1. Are you still going to write that part 2 of your book? I know you're super busy, just curious. – RunnyKine Oct 9 '13 at 17:38
@RunnyKine Thanks. Re: book - yes, I am going to, although it is not yet clear what the format of it will be, or set the exact time frame for it. – Leonid Shifrin Oct 9 '13 at 17:42
Thanks for replying. Good to know. The first one is a classic by the way. – RunnyKine Oct 9 '13 at 17:45
@RunnyKine Well, thanks :) I wrote it when I knew so much less than I do now (which I do in a big part due to this community), and I can see many flaws in the book now - so it's always good to know that it is not totally bad :) – Leonid Shifrin Oct 9 '13 at 17:47
Thanks, Leonid - very fast! – martin Oct 9 '13 at 18:21
MapThread[If[SameQ[#1, #2], #1, 0] &, {m, n}]


or

Transpose[{m, n}] /. {p_, q_} :> If[SameQ[p, q], p, 0]

-
Many thanks, Chris! – martin Oct 9 '13 at 17:24
Inner[ If[ #1 === #2, #1, 0] &, m, n, List]

{0, b, 0, d, d, 0}


or with Transpose and Apply:

If[#1 === #2, #1, 0] & @@@ Transpose[{m, n}]

-

Here's an unconventional way, which I think should be reasonably fast (thanks to Leonid for spotting a flaw):

Replace[m + n, _Plus -> 0, {1}] / 2
(* {0, b, 0, d, d, 0} *)


The idea is that a + b will have the head Plus, whereas a + a is 2 a, which has the head Times. Needless to say, a severe drawback of this approach is when the elements of the lists are numbers...

-
+1, this is a nice one. – Leonid Shifrin Oct 9 '13 at 17:58
@LeonidShifrin Oops... Thanks! :D – R. M. Oct 9 '13 at 17:59
+1. Yeah this is nice. – RunnyKine Oct 9 '13 at 18:03

And yet another variation using rules:

Thread@{m, n} /. {{p_, p_} :> p, {_, _} :> 0}


(Also Thread instead of Transpose for extra differenceness)

-

Here's a straightforward approach quite similar to your first attempt, which has the feature that it will work for numbers as well as symbols.

m = {1, b, c, 5.0, d, f};
n = {3, b, a, 5.0, d, e};
Table[If[m[[i]] === n[[i]], m[[i]], 0], {i, Length[m]}]

{0, b, 0, 5., d, 0}

-
m (1 - Sign[Length /@ (m - n)])
(*{0, b, 0, d, d, 0}*)

-

My solution:

m * Boole@MapThread[SameQ, {m, n}]


{0, b, 0, d, d, 0}

And here's the comparison:

m = RandomChoice[{a, b, c, d, e, f, g, h, i, j, k}, 1000000];
n = RandomChoice[{a, b, c, d, e, f, g, h, i, j, k}, 1000000];

(*Leonid Shifrin*)
m*(1 - Block[{Unitize}, _Unitize = 1; #] &[Unitize[m - n]]); // AbsoluteTiming

(*Artes*)
Inner[If[#1 === #2, #1, 0] &, m, n, List]; // AbsoluteTiming

(*Artes*)
If[#1 === #2, #1, 0] & @@@ Transpose[{m, n}]; // AbsoluteTiming

(*Chris Degnen*)
MapThread[If[SameQ[#1, #2], #1, 0] &, {m, n}]; // AbsoluteTiming

(*Chris Degnen*)
Transpose[{m, n}] /. {p_, q_} :> If[SameQ[p, q], p, 0]; // AbsoluteTiming

(*rm-rf*)
Replace[m + n, _Plus -> 0, {1}]/2; // AbsoluteTiming(*rm-rf*)

(*wxffles*)
Thread@{m, n} /. {{p_, p_} :> p, {_, _} :> 0}; // AbsoluteTiming

(*chyaong*)
m (1 - Sign[Length /@ (m - n)]); // AbsoluteTiming

(*RunnyKine*)
n*Replace[m/n, {1 -> 1, _ -> 0}, {1}]; // AbsoluteTiming

(*alephalpha*)
m * Boole@MapThread[SameQ, {m, n}]; // AbsoluteTiming


{5.359334, Null}
{1.688222, Null}
{1.920503, Null}
{1.629107, Null}
{2.132745, Null}
{1.964956, Null}
{1.396690, Null}
{3.478013, Null}
{3.582479, Null}
{1.933204, Null}

-
@Artes It refers to Loenid's one. – alephalpha Oct 11 '13 at 16:32

With inspiration from rm -rf here's one that should also work with numbers (If there are no zeros).

n * Replace[m / n, {1 -> 1, _ -> 0}, {1}]


{0, b, 0, d, d, 0}

-

Here is another one:

m * (1 - Abs[MapThread[Order, {m, n}]])

-

Idea of sparseArray can be pretty useful in case of large matrices or on extending it to multi-dimensional.

Block[{m = {a, b, c, d, d, f}, n = {b, b, a, d, d, e}, sep,
sum}, {sep = ArrayPad[#, {0, Length[m] - Length[#]}] & /@
Flatten[Normal[SparseArray[{1, #} -> n[[#]]]] & /@
Flatten[Position[Subtract[m, n], 0]], 1],
sum = ConstantArray[0, Length[m]]};
Table[sum = sep[[i]] + sum, {i, Length[sep]}] // Last]


{0, b, 0, d, d, 0}

-